zoukankan      html  css  js  c++  java
  • 【LeetCode】Array

    [11] Container With Most Water [Medium]

    O(n^2)的暴力解法直接TLE。

    正确的解法是Two Pointers。 O(n)的复杂度。保持两个指针i,j;分别指向长度数组的首尾。如果ai 小于aj,则移动i向后(i++)。反之,移动j向前(j--)。如果当前的area大于了所记录的area,替换之。这个想法的基础是,如果i的长度小于j,无论如何移动j,短板在i,不可能找到比当前记录的area更大的值了,只能通过移动i来找到新的可能的更大面积。

     1 class Solution {
     2 public:
     3     int maxArea(vector<int>& height) {
     4         int i = 0;
     5         int j = height.size() - 1;
     6         int ans = 0;
     7         while(i < j) {
     8             int area = (j - i) * min(height[i], height[j]);
     9             ans = max(ans, area);
    10             if (height[i] <= height[j]) {
    11                 ++i;
    12             }
    13             else {
    14                 --j;
    15             }
    16         }
    17         return ans;
    18     }
    19 };
    View Code

    [15] 3Sum [Medium]

    它要求返回结果不重复,所以去重。不能用unique,会TLE,直接在循环里面跳过。

    先排序,两根指针,夹逼定理

     1 class Solution {
     2 public:
     3     vector<vector<int>> threeSum(vector<int>& nums) {
     4         vector<vector<int>> result;
     5         if (nums.size() < 3) {
     6             return result;
     7         }
     8         sort(nums.begin(), nums.end());
     9         for (int i = 0; i < nums.size(); ) {
    10             int j = i + 1;
    11             int k = nums.size() - 1;
    12             while (j < k) {
    13                 if (nums[i] + nums[j] + nums[k] == 0) {
    14                     result.push_back(vector<int>{nums[i], nums[j], nums[k]});
    15                     ++j, --k;
    16                     while (j < k && nums[j-1] == nums[j]) { ++j; }
    17                     while (j < k && nums[k+1] == nums[k]) { --k; }
    18                 }
    19                 else if (nums[i] + nums[j] + nums[k] < 0) {
    20                     ++j;
    21                     while (j < k && nums[j-1] == nums[j]) { ++j; }
    22                 }
    23                 else {
    24                     --k;
    25                     while (j < k && nums[k+1] == nums[k]) { --k; }
    26                 }
    27             }
    28             ++i;
    29             while (nums[i-1] == nums[i]) { ++i; }
    30         }
    31         return result;
    32     }
    33 };
    View Code

    [16] 3Sum Closest [Medium]

    三个数求和,返回离target最近的和。

    Two Pointers, 跟15题一样, 先排序,两根指针左右夹逼。

     1 class Solution {
     2 public:
     3     int threeSumClosest(vector<int>& nums, int target) {
     4         int result = 0;
     5         int min_gap = INT_MAX;
     6         sort(nums.begin(), nums.end());
     7         for (int i = 0; i < nums.size() - 2; ++i) {
     8             int start = i + 1, end = nums.size() - 1;
     9             while (start < end) {
    10                 int temp = nums[i] + nums[start] + nums[end];
    11                 int gap = abs(temp - target);
    12                 if (gap < min_gap) {
    13                     min_gap = gap;
    14                     result = temp;
    15                 }
    16                 if (temp == target) break;
    17                 if (temp > target) {
    18                     --end;
    19                 }
    20                 else if (temp < target) {
    21                     ++start;
    22                 }
    23             }
    24         }
    25         return result;
    26     }
    27 };
    View Code

    [17] 4Sum [Medium]

    四个数求和,求出和target相等的元组, 思路和3sum一个样,包括和去重的方式都一样。

    还是先排序,然后两根指针。

     1 class Solution {
     2 public:
     3     vector<vector<int>> fourSum(vector<int>& nums, int target) {
     4         vector<vector<int>> result;
     5         if (nums.size() < 4) {
     6             return result;
     7         }
     8         sort(nums.begin(), nums.end());
     9         for (int i = 0; i < nums.size()-3; ) {
    10             for(int j = i+1; j < nums.size()-2; ) {
    11                 int start = j + 1, end = nums.size() - 1;
    12                 while (start < end) {
    13                     int sum = nums[i] + nums[j] + nums[start] + nums[end];
    14                     if (sum == target) {
    15                         result.push_back(vector<int>{nums[i], nums[j], nums[start], nums[end]});
    16                         ++start, --end;
    17                         while (start < end && nums[start-1] == nums[start]) {
    18                             ++start;
    19                         }
    20                         while (start < end && nums[end+1] == nums[end]) {
    21                             --end;
    22                         }
    23                     }
    24                     else if (sum < target) {
    25                         ++start;
    26                         while (start < end && nums[start-1] == nums[start]) {
    27                             ++start;
    28                         }
    29                     }
    30                     else {
    31                         --end;
    32                         while (start < end && nums[end+1] == nums[end]) {
    33                             --end;
    34                         }
    35                     }
    36                 }
    37                 ++j;
    38                 while (nums[j-1] == nums[j]) { ++j; }
    39             }
    40             ++i;
    41             while(nums[i-1] == nums[i]) { ++i; }
    42         }
    43         return result;
    44     }
    45 };
    View Code

    [45] Jump Game II [Hard]

    这个题需要记忆。再考肯定不会。。。要记忆。。。

    给你一个数组,数组元素的值是从当前index最多能往前面移动的步数,求到数组末尾最少移动的步数。

    我是参考了这个:https://www.tianmaying.com/tutorial/LC45

     1 /*
     2 将每个位置都看作一个点,并从第i个点向它之后的nums[i]个点都连一条长度为1的有向边,而现在的问题就是从0号点到达size-1号点需要的最短距离,这就是一个很简单的最短路问题,实际上由于边的长度均为1,而且不存在环,我们可以用宽度优先搜索(时间复杂度为O(n^2),即边数)来进行相关的计算。
     3 
     4 不难发现,这道题目转换出的最短路问题存在三个条件:
     5 
     6 边的长度均为1
     7 不存在环
     8 连出的边是连续的
     9 我们是不是可以用这三个“很强”的条件来做一些优化呢,答案自然是肯定的!
    10 
    11 ——如果令f[i]表示从0号点到达i号点的最短路径,那么对于任意i<j,有f[i]<=f[j],即f是非递减的,这个结论的证明是显然的,在此不作过多赘述。
    12 
    13 在有了这样的结论之后,我们就会发现,其实对于f数组来说,它会是一段段的存在,先是一个0,然后是一段1,然后是一段2,依此类推,那么现在问题来了,每一段的长度是多少呢?
    14 
    15 这个问题很好回答,如果我们令l[k]表示f数组中值为k的一段的左边界,r[k]表示f数组中值为k的一段的有边界,那么有
    16 
    17 l[k] = r[k - 1] + 1,这是显然的
    18 r[k] = max{i + nums[i] | l[k - 1] <= i <= r[k - 1]},由于f值为k的位置一定是从f值为k-1的位置走来的,所以只需要看从所有f值为k-1的位置里最远可以到达的地方即可。
    19 也就是说,我们可以在对nums的一遍扫描中,依次求出所有的l[k]和r[k],而f数组也就自然求解出来了——答案也就得到了。
    20 */
    View Code
     1 class Solution {
     2 public:
     3     int jump(vector<int>& nums) {
     4         int k = 0, l = 0, r = 0;
     5         while (r < nums.size()-1) {
     6             int next_r = r;
     7             for (int i = l; i <= r; ++i) next_r = max(next_r, nums[i]+i);
     8             ++k; l = r + 1; r = next_r; 
     9         }
    10         return k;
    11     }
    12 };
    View Code

    [48] Rotate Image [Medium]

    题目要求一个方阵顺时针旋转90°。

    经过研究发现顺时针旋转90°,相当于先转置,再每行逆序。要学会矩阵转置的写法

     1 class Solution {
     2 public:
     3     void rotate(vector<vector<int>>& matrix) {
     4         const int N = matrix.size();
     5         //trans
     6         for (int i = 0; i < N; ++i) {
     7             for (int j = i+1; j < N; ++j) {
     8                 swap(matrix[i][j], matrix[j][i]);
     9             }
    10         }
    11         
    12         //reverse
    13         for (int i = 0; i < N; ++i) {
    14             int start = 0, end = N - 1;
    15             while (start < end) {
    16                 swap(matrix[i][start++], matrix[i][end--]);
    17             }
    18         }
    19     }
    20 };
    View Code

    [54] Spiral Matrix [Medium]

    打印旋转矩阵。 设置有用的四个变量 beginx, beginy, endx, endy。然后用一个i去遍历。

     1 class Solution {
     2 public:
     3     vector<int> spiralOrder(vector<vector<int>>& matrix) {
     4         vector<int> ans;
     5         if (matrix.size() == 0) {
     6             return ans;
     7         }
     8         const int m = matrix.size();
     9         const int n = matrix[0].size();
    10         int beginx = 0, beginy = 0;
    11         int endx = n-1, endy = m - 1;
    12         while (true) {
    13             for (int i = beginx; i <= endx; ++i) {
    14                 ans.push_back(matrix[beginy][i]);
    15             }
    16             ++beginy;
    17             if (beginy > endy) break;
    18             
    19             for (int i = beginy; i <= endy; ++i) {
    20                 ans.push_back(matrix[i][endx]);
    21             }
    22             --endx;
    23             if (beginx > endx) break;
    24             
    25             for (int i = endx; i >= beginx; --i) {
    26                 ans.push_back(matrix[endy][i]);
    27             }
    28             --endy;
    29             if (beginy > endy) break;
    30             
    31             for (int i = endy; i >= beginy; --i) {
    32                 ans.push_back(matrix[i][beginx]);
    33             }
    34             ++beginx;
    35             if (beginx > endx) break;
    36         }        
    37         return ans;
    38     }
    39 };
    View Code

    [56] Merge Intervals [Hard]

    合并线段(数轴) 参考57题。 在 Insert Interval的基础上,一个新的interval集合,然后每次从旧的里面取一个interval出来,然后插入到新的集合中。

     1 /**
     2  * Definition for an interval.
     3  * struct Interval {
     4  *     int start;
     5  *     int end;
     6  *     Interval() : start(0), end(0) {}
     7  *     Interval(int s, int e) : start(s), end(e) {}
     8  * };
     9  */
    10 class Solution {
    11 public:
    12     vector<Interval> merge(vector<Interval>& intervals) {
    13         vector<Interval> ans;
    14         if (intervals.size() == 0) {
    15             return ans;
    16         }
    17         ans.push_back(intervals[0]);
    18         for (int i = 1; i < intervals.size(); ++i) {
    19             insert_interval(ans, intervals[i]);
    20         }
    21         return ans;
    22     }
    23     vector<Interval> insert_interval(vector<Interval>& intervals, Interval newInterval) {
    24         vector<Interval>::iterator it = intervals.begin();
    25         while (it != intervals.end()) {
    26             if (it->start > newInterval.end) {
    27                 break;    
    28             }
    29             else if (it->end < newInterval.start) {
    30                 it++;
    31                 continue;
    32             }
    33             else {
    34                 newInterval.start = min(newInterval.start, it->start);
    35                 newInterval.end = max(newInterval.end, it->end);
    36                 intervals.erase(it);
    37             }
    38         }
    39         intervals.insert(it, newInterval);
    40         return intervals;
    41     }
    42 };
    View Code

    [57] Insert Interval [Hard]

    先判断是否能放在最前面,然后在现有的intervals中一个一个遍历。有覆盖就更新newInterval,然后把原本的那段删除。

     1 /**
     2  * Definition for an interval.
     3  * struct Interval {
     4  *     int start;
     5  *     int end;
     6  *     Interval() : start(0), end(0) {}
     7  *     Interval(int s, int e) : start(s), end(e) {}
     8  * };
     9  */
    10 class Solution {
    11 public:
    12     vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
    13         vector<Interval>::iterator it = intervals.begin();
    14         while (it != intervals.end()) {
    15             if (it->start > newInterval.end) {
    16                 break;
    17             }
    18             else if (it->end < newInterval.start) {
    19                 ++it;
    20                 continue;
    21             }
    22             else {
    23                 newInterval.start = min(it->start, newInterval.start);
    24                 newInterval.end = max(it->end, newInterval.end);
    25                 intervals.erase(it);
    26             }
    27         }
    28         intervals.insert(it, newInterval);
    29         return intervals;
    30     }
    31 };
    View Code

    [59] Spiral Matrix II [Medium]

    跟前一题Spiral Matrix的区别是前一题是遍历, 这个题是造一个矩阵出来。 思路写法都一样。

     1 class Solution {
     2 public:
     3     vector<vector<int>> generateMatrix(int n) {
     4         vector<vector<int>> matrix(n, vector<int>(n, 0));
     5         if (n == 0) {
     6             return matrix;
     7         }
     8         int number = 1;
     9         int beginx = 0, beginy = 0, endx = n - 1, endy = n - 1;
    10         while (true) {
    11             for (int i = beginx; i <= endx; ++i) {
    12                 matrix[beginy][i] = number++;
    13             }
    14             ++beginy;
    15             if (beginy > endy) { break; }
    16             
    17             for (int i = beginy; i <= endy; ++i) {
    18                 matrix[i][endx] = number++;
    19             }
    20             --endx;
    21             if (beginx > endx) { break; }
    22 
    23             for (int i = endx; i >= beginx; --i) {
    24                 matrix[endy][i] = number++;
    25             }            
    26             --endy;
    27             if (beginy > endy) { break; }
    28             
    29             for (int i = endy; i >= beginy; --i) {
    30                 matrix[i][beginx] = number++;
    31             }
    32             ++beginx;
    33             if (beginx > endx) { break; }
    34         }
    35         return matrix;
    36     }
    37 };
    View Code

    [73] Set Matrix Zeroes [Medium]

    如果矩阵中一个元素为0, 那么把该元素所在的行和列都置零。O(1)的空间复杂度

    思路:有个简单的O(m+n)的空间复杂度的,就是设两个布尔数组,来控制行和列是否为0.

    但是如果要降低到O(1)的话,就可以牺牲第0行和第0列来存这两个数组。提前用两个变量保存好第0行,第0列是否置0.

     1 class Solution {
     2 public:
     3     void setZeroes(vector<vector<int>>& matrix) {
     4         const int m = matrix.size();
     5         if (m == 0) return;
     6         const int n = matrix[0].size();
     7         bool row_has_zero = false;
     8         bool col_has_zero = false;
     9         for (size_t i = 0; i < m; ++i) {
    10             if (matrix[i][0] == 0) {
    11                 col_has_zero = true;
    12                 break;
    13             }
    14         }
    15         for (size_t j = 0; j < n; ++j) {
    16             if (matrix[0][j] == 0) {
    17                 row_has_zero = true;
    18                 break;
    19             }
    20         }
    21         
    22         for (size_t i = 1; i < m; ++i) {
    23             for (size_t j = 1; j < n; ++j) {
    24                 if (matrix[i][j] == 0) {
    25                     matrix[i][0] = 0;
    26                     matrix[0][j] = 0;
    27                 }
    28             }
    29         }
    30         
    31         for (size_t i = 1; i < m; ++i) {
    32             for (size_t j = 1; j < n; ++j) {
    33                 if (matrix[i][0] == 0 || matrix[0][j] == 0) {
    34                     matrix[i][j] = 0;
    35                 }
    36             }
    37         }
    38         
    39         if (col_has_zero == true) {
    40             for (size_t i = 0; i < m; ++i) {
    41                 matrix[i][0] = 0;
    42             }
    43         }
    44         
    45         if (row_has_zero == true) {
    46             for (size_t j = 0; j < n; ++j) {
    47                 matrix[0][j] = 0;
    48             }
    49         }
    50         return;
    51     }
    52 };
    View Code

    [118] Pascal's Triangle [Easy]

     1 class Solution {
     2 public:
     3     vector<vector<int>> generate(int numRows) {
     4         vector<vector<int>> ans;
     5         if (numRows == 0) return ans;
     6         for (size_t i = 0; i < numRows; ++i) {
     7             vector<int> ans_row(i+1, 1);
     8             if (i == 0 || i == 1) {
     9                 ans.push_back(ans_row);
    10                 continue;
    11             }
    12             for (size_t j = 1; j < i ; ++j) {
    13                 ans_row[j] = ans[i-1][j-1] + ans[i-1][j];
    14             }
    15             ans.push_back(ans_row);
    16         }
    17         return ans;
    18     }
    19 };
    View Code

    [119] Pascal's Triangle II [Easy]

    只要求O(k)的额外空间。我自己写的解法用了两个数组,其实一个就够了。

     1 class Solution {
     2 public:
     3     vector<int> getRow(int rowIndex) {
     4        vector<int> ans(rowIndex+1, 1);
     5        vector<int> help(rowIndex+1, 0);
     6        if (rowIndex == 0 || rowIndex == 1) {
     7            return ans;
     8        }
     9        for (size_t i = 2; i < rowIndex+1; ++i) {
    10            help = ans;
    11            for (size_t j = 1; j < i; ++j) {
    12                 ans[j] = help[j-1] + help[j];       
    13            }
    14            ans[i] = 1;
    15        }
    16        return ans;
    17     }
    18 };
    View Code

    一个数组的还没看懂(好困,睡了==)

     1 class Solution {
     2 public:
     3     vector<int> getRow(int rowIndex) {
     4         vector<int> A(rowIndex+1, 0);
     5         A[0] = 1;
     6         for(int i=1; i<rowIndex+1; i++)
     7             for(int j=i; j>=1; j--)
     8                 A[j] += A[j-1];
     9         return A;
    10     }
    11 };
    View Code
  • 相关阅读:
    cf1100 F. Ivan and Burgers
    cf 1033 D. Divisors
    LeetCode 17. 电话号码的字母组合
    LeetCode 491. 递增的子序列
    LeetCode 459.重复的子字符串
    LeetCode 504. 七进制数
    LeetCode 3.无重复字符的最长子串
    LeetCode 16.06. 最小差
    LeetCode 77. 组合
    LeetCode 611. 有效三角形个数
  • 原文地址:https://www.cnblogs.com/zhangwanying/p/6136030.html
Copyright © 2011-2022 走看看