An analysis of leetcode's solution to 214-220 questions

Posted by manmanman on Thu, 25 Jun 2020 11:58:16 +0200

  1. Shortest palindrome string
    Given a string s, you can convert it to a palindrome string by adding characters before the string. Find and return the shortest palindrome string that can be converted in this way.

You can use horse drawn cart to get the longest palindrome substring, and then add it in reverse. It can also be solved by KMP

class Solution {
public:
    string shortestPalindrome(string s)
    {
        int n = s.size();
        string rev(s);
        reverse(rev.begin(), rev.end());
        string s_new = s + "#" + rev;
        int n_new = s_new.size();
        vector<int> f(n_new, 0);
        for (int i = 1; i < n_new; i++) {
            int t = f[i - 1];
            while (t > 0 && s_new[i] != s_new[t])
                t = f[t - 1];
            if (s_new[i] == s_new[t])
                ++t;
            f[i] = t;
        }
        return rev.substr(0, n - f[n_new - 1]) + s;
    }
};
  1. The K-th largest element in the array
    The k-th largest element was found in the unsorted array. Note that you need to look for the k-th largest element after array sorting, not the k-th different element.

When you see the K elements, you know that the heap can be solved. In addition, you can use the selection algorithm. The idea of selecting algorithm is to divide and conquer

#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;

class Solution
{
public:
    int findKthLargest(vector<int> &nums, int k)
    {
        int result = 0;
        int numsSize = int(nums.size());
        if (numsSize == 0 || k > numsSize)
        {
            return 0;
        }
        //Find the smallest number in kMIN
        int kMin = numsSize - k + 1;
        result = select(nums, 0, numsSize - 1, kMin);
        return result;
    }

    int select(vector<int> &nums, int left, int right, int target)
    {
        if (left == right)
        {
            return nums[left];
        }
        int cut = partition(nums, left, right);
        //Element with current result small
        int currentResult = cut - left + 1;
        if (target == currentResult)
        {
            return nums[cut];
        }
        else if (target < currentResult)
        {
            return select(nums, left, cut - 1, target);
        }
        else
        {
            //Find the next small number of target - currentResult
            return select(nums, cut + 1, right, target - currentResult);
        }
        return 0;
    }

    int partition(vector<int> &nums, int left, int right)
    {
        int cut = nums[right];
        //i points to the leftmost number of the heap, and j points to the number of the next judgment
        int i = left;
        for (int j = left; j < right; j++)
        {
            if (nums[j] <= cut)
            {
                exchange(nums[i], nums[j]);
                i++;
            }
        }
        exchange(nums[i], nums[right]);
        return i;
    }

    void exchange(int &a, int &b)
    {
        int tmpInt = a;
        a = b;
        b = tmpInt;
        return;
    }
};

  1. Combined sum 3
    Find out the combination of all k numbers whose sum is n. Only positive integers of 1 - 9 are allowed in a combination, and there are no duplicate numbers in each combination.

This problem can be easily solved by backtracking

class Solution {
public:
    vector<vector<int>> combinationSum3_dfs(int k, int n, int now, int status) {
        if(k == 0 && n == 0) {  //A useful result
            vector<int> res;
            for(int i = 1; i < 10; i++) {
                if((2 << i) & status) res.push_back(i);
            }
            return {res};
        }
        vector<vector<int>> res;
        while(now < 10 && n >= now) {   //The condition of continuous dfs
            auto r = combinationSum3_dfs(k - 1, n - now, now + 1, status | (2 << now));
            res.insert(res.end(), r.begin(), r.end()); //Result merging
            now++;
        }
        return res;
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        return combinationSum3_dfs(k, n, 1, 0);
    }
};

  1. There are duplicate elements
    Given an array of integers, determine whether there are duplicate elements.
    If any value appears in the array at least twice, the function returns true. Returns false if each element in the array is different.

Very simple question, hash table storage and search

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        std::unordered_map<int, int> map;
        for (auto i : nums)
        {
            map[i]++;
            if (map[i] > 1)
                return true;
        }
        return false;
    }
};
  1. The problem of skyline

There are many solutions to this problem: the most intuitive solution is to scan the scanning line from left to right once, compare the various heights saved in the current X-axis, and output the highest value. In the same way, we can use double linked list to scan. In addition, we can also adopt the idea of divide and Conquer: no building is 0, one building is the value, and many buildings are divided and conquer.

class Solution {
public:
    vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
        multiset<pair<int, int>> all;
        vector<vector<int>> res;
        
        for (auto& e : buildings) {
            all.insert(make_pair(e[0], -e[2])); // critical point, left corner
            all.insert(make_pair(e[1], e[2])); // critical point, right corner
        }
        
        multiset<int> heights({0}); // Saves all heights in the current location.
        vector<int> last = {0, 0}; // Saves the abscissa and height of the previous position
        for (auto& p : all) {
            if (p.second < 0) heights.insert(-p.second); // Left end, height in pile
            else heights.erase(heights.find(p.second)); // Right endpoint, remove height
            
            // Current key, maximum height
            auto maxHeight = *heights.rbegin();
            
            // If the current maximum height is different from the previous height, it means that this is a turning point
            if (last[1] != maxHeight) {
                // Update last and add result set
                last[0] = p.first;
                last[1] = maxHeight;
                res.push_back(last);
            }
        }
        
        return res;
    }
};

  1. Duplicate element 2 present
    Given an integer array and an integer k, it is determined whether there are two different indexes I and j in the array, so that nums [i] = nums [j], and the absolute value of the difference between I and j is at most K.

It's as simple as the first problem. The hash table is solved directly, but here's an optimization detail: we don't need to store all the numbers, just use a sliding window of size k

class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) {
        unordered_map<int, vector<int>> map;
        for (int i = 0; i < nums.size(); i++)
        {
            map[nums[i]].push_back(i);
            if (map[nums[i]].size() > 1)
            {
                for (int j = 1; j < map[nums[i]].size(); j++)
                {
                    if (map[nums[i]][j] - map[nums[i]][j - 1] <= k)
                        return true;
                }
            }
        }
        return false;
    }
};
  1. Duplicate element 3 present
    In the integer array nums, whether there are two subscripts I and j, so that the absolute value of the difference between nums [i] and nums [j] is less than or equal to t, and the absolute value satisfying the difference between I and j is also less than or equal to.
    Returns true if it exists, and false if it does not exist.

There are many ways to solve this problem. The best way is the idea of bucket sorting or the way of sliding window

class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        if (k < 1 || t < 0 || nums.empty()) return false;
        int N = nums.size();
        map<long, int> m{{nums[0], 1}};
        for (int i = 1; i < N; ++i) {
            auto it = m.lower_bound(nums[i]);
            if (it != m.end() && abs(it->first - (long)nums[i]) <= t) return true;
            if (it != m.begin() && abs((--it)->first - (long)nums[i]) <= t)  return true;
            ++m[nums[i]];
            if (i - k >= 0 && --m[nums[i - k]] == 0) m.erase(nums[i - k]);
        }
        return false;
    }
};



Topics: less