【Leetcode真题】数组中的问题其实最常见

写在前面:首先,在这里祝大家新年快乐啊,新年第一篇原创,感谢大家的支持,虽然粉丝不多,浏览量不多,但是我还是会继续加油努力的!!!!

第一个问题 Move Zeros:

原题
Given an array nums, write a function to move all 0’s to the end of it while maintaining the relative order of the non-zero elements.
Example:
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]

解法1:

#include <iostream>
#include <vector>

using namespace std;

// Time Complexity: O(n) 时间复杂度
// Space Complexity: O(n)  空间复杂度
class Solution {
public:
    void moveZeroes(vector<int>& nums) {

        vector<int> nonZeroElements;

        for (int i = 0; i < nums.size(); i++) {
            if(nums[i]){
                nonZeroElements.push_back(nums[i]);
            }
        }
        for (int j = 0; j < nonZeroElements.size(); j++) {
            nums[j] = nonZeroElements[j];
        }
        for (int k = nonZeroElements.size(); k < nums.size(); k++) {
            nums[k] = 0;
        }
    }
};

解法2:

#include <iostream>
#include <vector>

using namespace std;

// Time Complexity: O(n)
// Space Complexity: O(1)
class Solution {
public:
    void moveZeroes(vector<int>& nums) {

       int k = 0;
        for (int i = 0; i < nums.size(); i++) {
            if(nums[i]){
                nums[k++] = nums[i];
            }
        }
        for (int j = k; j < nums.size(); j++) {
            nums[j] = 0;
        }
    }
};

解法3:

#include <iostream>
#include <vector>

using namespace std;

// Time Complexity: O(n)
// Space Complexity: O(1)
class Solution {
public:
    void moveZeroes(vector<int>& nums) {

        int k = 0;
        for (int i = 0; i < nums.size(); i++) {
            if(nums[i]){
                swap(nums[i],nums[k++]);
            }
        }
    }
};

解法4:

#include <iostream>
#include <vector>

using namespace std;
// Time Complexity: O(n)
// Space Complexity: O(1)
class Solution {
public:
    void moveZeroes(vector<int>& nums) {

        int k = 0; // keep nums[0...k) are all zero elements
        for(int i = 0 ; i < nums.size() ; i ++ )
            if(nums[i])
                // avoid self swapping
                if(k != i)
                    swap(nums[k++], nums[i]);
                else
                    k ++;
    }
};
从上面4种解法可以看出,一道简单的移动元素的题目就能有如此多的优化方法,但是,在我们没想到优化方法的时候,无论什么时候我们都可以尝试使用暴力破解方法!

第二个问题:Remove Element

原题
Given an array nums and a value val, remove all instances of that value in-place and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
The order of elements can be changed. It doesn’t matter what you leave beyond the new length.
Example 1:
Given nums = [3,2,2,3], val = 3,
Your function should return length = 2, with the first two elements of nums being 2.
It doesn’t matter what you leave beyond the returned length.
Example 2:
Given nums = [0,1,2,2,3,0,4,2], val = 2,
Your function should return length = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4.
Note that the order of those five elements can be arbitrary.
It doesn’t matter what values are set beyond the returned length.

解法一:

#include <iostream>
#include <vector>
#include <cassert>
#include <stdexcept>

using namespace std;


/// Two Pointers
///Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {

public:
    int removeElement(vector<int>& nums, int val) {
        int val1 = 0;
        for (int i = 0; i < nums.size(); i++) {
            if(nums[i] != val){
                nums[val1++] = nums[i];
            }
        }
        return val1;
    }
};

解法2:

#include <iostream>
#include <vector>
#include <cassert>
#include <stdexcept>

using namespace std;

/// Two Pointers
/// Move the deleted element to the last
/// This method would be save the unnecessary copy when the removed element is rare.
///
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {

public:
    int removeElement(vector<int>& nums, int val) {

        int newl = nums.size();
        int i = 0;

        while (i < newl){
            if(nums[i] == val){
                nums[i] = nums[--newl];
            } else{
                i++;
            }
        }
        return newl;
    }
};

第三个问题:Remove Duplicates from Sorted Array

原题
Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
Example 1:
Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn’t matter what you leave beyond the returned length.
Example 2:
Given nums = [0,0,1,1,1,2,2,3,3,4],
Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively.
It doesn’t matter what values are set beyond the returned length.

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.size() == 0){
            return 0;
        }

        int res = 1;
        int index = nextDifferentCharacterIndex(nums, 1);
        int i = 1;
        while (index<nums.size()){
            res++;
            nums[i++] = nums[index];
            index = nextDifferentCharacterIndex(nums, index+1);
        }

        return res;

    }


private:
    int nextDifferentCharacterIndex(const vector<int> &nums, int p) {
        for (; p < nums.size(); p++) {
            if (nums[p] != nums[p - 1]) {
                break;
            }
        }
        return p;
    }

};

第三个问题:Remove Duplicates from Sorted Array II

原题
Given a sorted array nums, remove the duplicates in-place such that duplicates appeared at most twice and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
Example 1:
Given nums = [1,1,1,2,2,3],
Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3 respectively.
It doesn’t matter what you leave beyond the returned length.
Example 2:
Given nums = [0,0,1,1,1,1,2,3,3],
Your function should return length = 7, with the first seven elements of nums being modified to 0, 0, 1, 1, 2, 3 and 3 respectively.
It doesn’t matter what values are set beyond the returned length.

#include <iostream>
#include <vector>

using namespace std;

/// Ad-Hoc
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {

        int i = 0;//记录调整后的数组长度
        int j = 0;//保存不相等元素索引值
        while(j < nums.size()){
            int k = nextIndex(nums, j);
            int len = min( 2, k-j);
            for(int ii = 0 ; ii < len ; ii ++)
                nums[i+ii] = nums[j];
            i += len;
            j = k;//j保存索引继续进行循环
        }

        return i;
    }

private:
    int nextIndex(const vector<int>& nums, int index){
        for(int i = index ; i < nums.size() ; i ++)
            if(nums[i] != nums[index])
                return i;
        return nums.size();
    }
};

第四个问题:Sort Colors

原题
Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
Note: You are not suppose to use the library’s sort function for this problem.
Example:
Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]

#include <iostream>
#include <vector>
#include <cassert>

using namespace std;

// Counting
// Time Complexity: O(n)  时间复杂度
// Space Complexity: O(3)  空间复杂度
class Solution {
public:
    void sortColors(vector<int> &nums) {

        int count[3] = {0};

        for (int i = 0; i < nums.size(); i++) {
            assert(nums[i] >= 0 & nums[i] <= 2);
            count[nums[i]]++;
        }

        int index = 0;
        for (int j = 0; j < count[0]; ++j) {
            nums[index++] = 0;
        }
        for (int k = 0; k < count[1]; k++) {
            nums[index++] = 1;
        }
        for (int l = 0; l < count[2]; l++) {
            nums[index++] = 2;
        }

    }
};

解法2:三路快排partition思路的应用 Sort Color

#include <iostream>
#include <vector>
#include <cassert>

using namespace std;

// Three Way Quick Sort
// Time Complexity: O(n)  时间复杂度
// Space Complexity: O(1)  空间复杂度
//比上一个优化了,只遍历一次数组便能解决问题
class Solution {
public:
    void sortColors(vector<int> &nums) {

        int zero = -1;          // [0...zero] == 0
        int two = nums.size();  // [two...n-1] == 2
        for(int i = 0 ; i < two ; ){
            if(nums[i] == 1)
                i ++;
            else if (nums[i] == 2)
                swap( nums[i] , nums[--two]);//此时的i不应该动,因为索引i的值还是未知的
            else{ // nums[i] == 0
                assert(nums[i] == 0);  //保证该数是0,1,2
                swap(nums[++zero] , nums[i++]);
            }
        }
    }
};

第五个问题:Merge Sorted Array

原题
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.
Note:
The number of elements initialized in nums1 and nums2 are m and n respectively.
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2.
Example:
Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]

#include <iostream>
#include <vector>
#include <cassert>

using namespace std;


/// Standard merge process in merge sort
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {

        assert(nums1.size() == m + n && nums2.size() == n);

        for(int i = n + m - 1 ; i >= n ; i -- )
            nums1[i] = nums1[i - n];

        int i = n;  // pointer for nums1 [n, n+m)
        int j = 0;  // pointer for nums2 [0, n)
        int k = 0;  // pointer merged nums1 [0, n+m)
        while( k < n + m ){
            if( i >= n+m )
                nums1[k++] = nums2[j++];
            else if( j >= n )
                nums1[k++] = nums1[i++];
            else if( nums1[i] < nums2[j] )
                nums1[k++] = nums1[i++];
            else
                nums1[k++] = nums2[j++];
        }
    }
};

第六个问题:Kth Largest Element in an Array

原题
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
Example 1:
Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:
Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {

        srand(time(NULL));
        return findKthLargest(nums, 0, nums.size()-1 , k - 1 );
    }

private:
    int findKthLargest(vector<int>& nums, int l, int r, int k){

        if( l == r )
            return nums[l];

        int p = partition(nums, l, r);

        if( p == k )
            return nums[p];
        else if( k < p )
            return findKthLargest(nums, l, p-1, k);
        else // k > p
            return findKthLargest(nums, p+1 , r, k);
    }

    int partition( vector<int>& nums, int l, int r ){

        int p = rand()%(r-l+1) + l;
        swap( nums[l] , nums[p] );

        int lt = l + 1; //[l+1...lt) > p ; [lt..i) < p
        for( int i = l + 1 ; i <= r ; i ++ )
            if( nums[i] > nums[l] )
                swap(nums[i], nums[lt++]);

        swap(nums[l], nums[lt-1]);

        return lt-1;
    }
};

第七个问题:Two Sum II - Input array is sorted

原题
Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.
Note:
Your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution and you may not use the same element twice.
Example:
Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.

解法一:利用该数组是有序的性质,从而利用二分法查找该元素

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        assert(numbers.size()>=2);

        for (int i = 0; i < numbers.size(); i++) {
            int j = binarySearch(numbers,i+1,numbers.size()-1,target-numbers[i]);
            if(j != -1){
                int res[2] = {i+1,j+1};
                return vector<int>(res,res+2);
            }
        }

        throw invalid_argument("the input has no solution");
    }

private:
    int binarySearch(const vector<int> &nums, int l, int r, int target){
        assert(l>=0 && l<nums.size());
        assert(r>=0 && r<nums.size());


        while (l<=r){
            int mid = (l+r)/2;
            if(target == nums[mid]){
                return mid;
            }
            if (target > nums[mid]){
                return l = mid+1;
            } else{
                return r = mid-1;
            }
        }
        return -1;
    }

    bool isSorted(const vector<int>& numbers){
        for(int i = 1 ; i < numbers.size() ; i ++)
            if(numbers[i] < numbers[i-1])
                return false;
        return true;
    }
};

解法二:利用对撞指针

#include <iostream>
#include <vector>
#include <cassert>

using namespace std;

// Two Pointers
// Time Complexity: O(n)
// Space Complexity: O(1)
class Solution {

public:
    vector<int> twoSum(vector<int>& numbers, int target) {

        assert(numbers.size() >= 2);
        // assert(isSorted(numbers));

        int l = 0, r = numbers.size() - 1;
        while(l < r){

            if(numbers[l] + numbers[r] == target){
                int res[2] = {l+1, r+1};
                return vector<int>(res, res+2);
            }
            else if(numbers[l] + numbers[r] < target)
                l ++;
            else // numbers[l] + numbers[r] > target
                r --;
        }

        throw invalid_argument("the input has no solution");
    }

第八个问题:Valid Palindrome

原题
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
Note: For the purpose of this problem, we define empty string as valid palindrome.
Example 1:
Input: “A man, a plan, a canal: Panama”
Output: true
Example 2:
Input: “race a car”
Output: false

#include <iostream>

using namespace std;


/// Two Pointers
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {

public:
    bool isPalindrome(string s) {
        int i = next_alpha_numeric(s,0);
        int j = prev_alpha_numeric(s,s.size()-1);

        while (i <= j){
            if(tolower(s[i]) != tolower(s[j])){
                return false;
            }

            i = next_alpha_numeric(s,i+1);
            j = prev_alpha_numeric(s,j-1);
        }
        return true;

    }

private:
    //正序
    int next_alpha_numeric(const string& s, int index){
        for (int i = index; i < s.size(); i++) {
            if(isalnum(s[i])){
                return i;
            }
        }
        return s.size();

    }
    //反序
    int prev_alpha_numeric(const string& s, int index){
        for (int i = index; i >= 0 ; i--) {
            if(isalnum(s[i])){
                return i;
            }
        }

        return -1;
    }
};

第九个问题:Container With Most Water

原题
Given n non-negative integers a1, a2, …, an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.

Example:
Input: [1,8,6,2,5,4,8,3,7]
Output: 49

解法一:暴力破解法

class Solution {
public:
    int maxArea(vector<int>& height) {

        assert(height.size() >= 2);

        int area = 0;
        for(int i = 0 ; i < height.size() ; i ++)
            for(int j = i + 1; j < height.size() ; j ++)
                area = max(area , min(height[i], height[j]) * (j - i));
        return area;
    }
};

解法2:对撞指针

#include <iostream>
#include <vector>
#include <cassert>

using namespace std;

/// Two Pointers
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {
public:
    int maxArea(vector<int>& height) {

        assert(height.size() >= 2);

        int l = 0, r = height.size() - 1;
        int area = 0;
        while(l < r){
            area = max(area , min(height[l], height[r]) * (r - l));
            if(height[l] < height[r])
                l ++;
            else
                r --;
        }
        return area;
    }
};

第十个问题:Minimum Size Subarray Sum

原题
Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn’t one, return 0 instead.
Example:
Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: the subarray [4,3] has the minimal length under the problem constraint.

利用滑块窗口解决,此题要注意什么时候才能移动滑

#include <iostream>
#include <cassert>
#include <vector>

using namespace std;


// Sliding Window
// Time Complexity: O(n)
// Space Complexity: O(1)
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        assert(s>0);
        int l = 0;
        int r = -1;
        int sum = 0;
        int res = nums.size()-1;

        while (l<nums.size()){
            if(r+1<nums.size() && sum<s){
                sum += nums[++r];
            } else{
                sum -= nums[l++];
            }

            if(sum>=s){
                res = min(res, r-l+1);
            }

        }
        return res == nums.size()-1 ? 0:res;
    }
};

第十一个问题:Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters.
Example 1:
Input: “abcabcbb”
Output: 3
Explanation: The answer is “abc”, with the length of 3.
Example 2:
Input: “bbbbb”
Output: 1
Explanation: The answer is “b”, with the length of 1.
Example 3:
Input: “pwwkew”
Output: 3
Explanation: The answer is “wke”, with the length of 3.
Note that the answer must be a substring, “pwke” is a subsequence and not a substring.

#include <iostream>
#include <string>
#include <cassert>

using namespace std;

// Sliding Window
// Time Complexity: O(len(s))
// Space Complexity: O(len(charset))
class Solution {
public:
    int lengthOfLongestSubstring(string s) {

        int freq[256] = {0};

        int l = 0;
        int r = -1;
        int res = 0;

        while (l < s.size()){
            if(r+1 < s.size() && freq[s[r+1]] == 0){
                freq[s[++r]]++;
            } else{
                freq[s[l++]]--;
            }
            res = max(res, r-l+1);
        }
        return res;
    }
};

这里利用了正则表示来求是否该元素是否重复,如果是0则没有重复,1是有重复

第十二个问题:Find All Anagrams in a String

原题
Given a string s and a non-empty string p, find all the start indices of p’s anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.
The order of output does not matter.
Example 1:
Input:
s: “cbaebabacd” p: “abc”
Output:
[0, 6]
Explanation:
The substring with start index = 0 is “cba”, which is an anagram of “abc”.
The substring with start index = 6 is “bac”, which is an anagram of “abc”.
Example 2:
Input:
s: “abab” p: “ab”
Output:
[0, 1, 2]
Explanation:
The substring with start index = 0 is “ab”, which is an anagram of “ab”.
The substring with start index = 1 is “ba”, which is an anagram of “ab”.
The substring with start index = 2 is “ab”, which is an anagram of “ab”.

#include <iostream>
#include <vector>
#include <string>
#include <cassert>

using namespace std;

/// Sliding Window
/// Time Complexity: O(len(p) + len(s))
/// Space Complexity: O(1)
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {

        vector<int> res;
        if(s.size() < p.size())
            return res;

        assert(p.size() > 0);

        vector<int> freq_p(26, 0);
        for(char c: p)
            freq_p[c - 'a'] += 1;

        vector<int> freq_s(26, 0);
        int l = 0, r = -1; // Sliding window: s[l, r]
        while(r + 1 < s.size()){
            r ++;
            freq_s[s[r] - 'a'] ++;
            if(r - l + 1 > p.size())
                freq_s[s[l++] - 'a'] --;

            if(r - l + 1 == p.size() && same(freq_s, freq_p))
                res.push_back(l);
        }

        return res;
    }

private:
    bool same(const vector<int>& freq_s, const vector<int>& freq_p){
        for(int i = 0 ; i < 26; i ++)
            if(freq_s[i] != freq_p[i])
                return false;
        return true;
    }
};

这里用到了滑块窗口和正则表达式

第十三个问题:Minimum Window Substring

原题

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
Example:
Input: S = “ADOBECODEBANC”, T = “ABC”
Output: "BANC"

#include <iostream>
#include <cassert>

using namespace std;

/// Sliding Window
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {
public:
    string minWindow(string s, string t) {

        int tFreq[256] = {0};
        for(int i = 0 ; i < t.size() ; i ++)
            tFreq[t[i]] ++;

        int sFreq[256] = {0};
        int sCnt = 0;

        int minLength = s.size() + 1;
        int startIndex = -1;

        int l = 0, r = -1;
        while(l < s.size()){

            if(r + 1 < s.size() && sCnt < t.size()){

                sFreq[s[r+1]] ++;
                if(sFreq[s[r+1]] <= tFreq[s[r+1]])   
                    sCnt ++;
                r ++;
            }
            else{
                assert(sCnt <= t.size());
                if(sCnt == t.size() && r - l + 1 < minLength){
                    minLength = r - l + 1;
                    startIndex = l;
                }

                sFreq[s[l]] --;
                if(sFreq[s[l]] < tFreq[s[l]])
                    sCnt --;
                l ++;
            }
        }

        if( startIndex != -1 )
            return s.substr(startIndex, minLength);

        return "";
    }
};

本次的分享到此结束了,第一次做leetcode上面的真题,感觉还是很有难度的,对一般的算法思路还是不太熟悉,未来要继续加油,本次分享仅仅之分享了代码,并没有做过多的注释,日后还会对此文章进行补充~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值