LeetCode 算法基础

在这里插入图片描述

二分查找

lc.34 排序数组中查找元素第一和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。

  • 二分
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> ans;
        if(!nums.empty()){
            int l = 0 , r = nums.size() - 1 ;
            while(l < r){
                int mid = l + r >> 1;
                if(nums[mid] >= target) r = mid;
                else l = mid + 1; 
            }
            if(nums[l] != target) ans.emplace_back(-1);
            else ans.emplace_back(l);
            l = 0 , r = nums.size() - 1 ;
            while(l < r){
                int mid = l + r + 1>> 1;
                if(nums[mid] <= target) l = mid;
                else r = mid - 1; 
            }
            if(nums[l] != target) ans.emplace_back(-1);
            else ans.emplace_back(l); 
        }
        else{
            ans.emplace_back(-1);
            ans.emplace_back(-1);
        }              
        return ans;
    }
};

得考虑一下数组空的情况。

lc.33 搜索旋转排序数组

整数数组 nums 按升序排列,数组中的值 互不相同
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

  • 二分
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int min = 1e4 , xbmin = 0 ;
        for(int i = 0 ; i < nums.size() ; i ++){
            if(nums[i] < min){
                min = nums[i];
                xbmin = i ;
            }
        }
        int l = 0 , r = xbmin - 1 ;
        while(l < r){
            int mid = l + r >> 1;
            if(nums[mid] >= target) r = mid;
            else l = mid + 1;
        }
        if(nums[l] == target) return l;
        l = xbmin , r = nums.size() - 1;
        while(l < r){
            int mid = l + r >> 1;
            if(nums[mid] >= target) r = mid;
            else l = mid + 1;
        }
        if(nums[l] == target) return l;
        return -1;
    }
};

lc.74 搜索二维矩阵

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:

每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
  • 二分
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m=matrix.size();
        int n=matrix[0].size();
        int size=m*n;
        int T=size-1;
        int H=0;
        while(H<T){
            int mid=(H+T)/2;
            int X=mid%n;
            int Y=mid/n;
            if(matrix[Y][X]<target){
                H=mid+1;
            }
            else if(matrix[Y][X]>target){
                T=mid-1;
            }
            else
                return true;
        }
        int X=H%n;
        int Y=H/n;
        if(matrix[Y][X]==target)
            return true;
        return false;
    }
};

lc.153 寻找旋转排序数组中的最小值

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:

若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

  • 找头
class Solution {
public:
    int findMin(vector<int>& nums) {
        for(int i = 0 ; i < nums.size() - 1 ; i ++){
            if(nums[i] >= nums[i + 1]) return nums[i + 1];
        }
        return nums[0];
    }
};

都没有用到二分。

  • 二分
class Solution {
public:
    int findMin(vector<int>& nums) {
        int low = 0;
        int high = nums.size() - 1;
        while (low < high) {
            int pivot = low + (high - low) / 2;
            if (nums[pivot] < nums[high]) {
                high = pivot;
            }
            else {
                low = pivot + 1;
            }
        }
        return nums[low];
    }
};

和判断一样快。理论与实际的差别吧。

lc.162 寻找峰值

峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞ 。
你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

和 lc.153 一样,也可以用一次 O(n) 的遍历解决。不过二分理论上更快。

  • 二分查找
class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int l = 0 , r = nums.size() -1 ;
        while(l < r){
            int mid = l + r >> 1;
            if(nums[mid+1] < nums[mid]) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

从中间值看起,哪侧更大往哪侧搜索。

双指针

lc.82 删除排序链表的重复元素

存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。
返回同样按升序排列的结果链表。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (!head) {
            return head;
        }
        
        ListNode* dummy = new ListNode(0, head);

        ListNode* cur = dummy;
        while (cur->next && cur->next->next) {
            if (cur->next->val == cur->next->next->val) {
                int x = cur->next->val;
                while (cur->next && cur->next->val == x) {
                    cur->next = cur->next->next;
                }
            }
            else {
                cur = cur->next;
            }
        }

        return dummy->next;
    }
};

由于头结点可能被删除,所以在头结点之前建立一个哑节点。

lc.15 三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

  • 超时(?)
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ans;
        vector<int> thi;
        int cnt = 0;
        sort(nums.begin(),nums.end());
        for(int i = 0 ; i < nums.size() ; i ++){
            int l = i + 1 , r = nums.size() - 1 ;
            while(l < r){
                if(nums[l] + nums[r] + nums[i] < 0) l ++;
                else if(nums[l] + nums[r] + nums[i] > 0) r --;
                else {
                    thi.emplace_back(nums[i]);
                    thi.emplace_back(nums[l]);
                    thi.emplace_back(nums[r]);
                    for(auto& it : ans){
                        if(it == thi) cnt ++;
                    }
                    if(cnt == 0) ans.emplace_back(thi);
                    thi.clear();
                    cnt = 0 ;
                    l++ ; r -- ;
                }
            }
        }
        return ans;
    }
};

在这里插入图片描述
超了,但没完全超。过了,但也没通过。

  • 官方题解
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        // 枚举 a
        for (int first = 0; first < n; ++first) {
            // 需要和上一次枚举的数不相同
            if (first > 0 && nums[first] == nums[first - 1]) {
                continue;
            }
            // c 对应的指针初始指向数组的最右端
            int third = n - 1;
            int target = -nums[first];
            // 枚举 b
            for (int second = first + 1; second < n; ++second) {
                // 需要和上一次枚举的数不相同
                if (second > first + 1 && nums[second] == nums[second - 1]) {
                    continue;
                }
                // 需要保证 b 的指针在 c 的指针的左侧
                while (second < third && nums[second] + nums[third] > target) {
                    --third;
                }
                // 如果指针重合,随着 b 后续的增加
                // 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
                if (second == third) {
                    break;
                }
                if (nums[second] + nums[third] == target) {
                    ans.push_back({nums[first], nums[second], nums[third]});
                }
            }
        }
        return ans;
    }
};

判断与上次枚举的数不同,以排除结果里相同的解。就不需要通过再遍历一遍来去重。

lc.844 比较含退格符的字符串

  • 开两个 vector 存退格结束的字符串
class Solution {
public:
    bool backspaceCompare(string s, string t) {
        vector<char> tmps , tmpt;
        for(int i = 0 ; i < s.size() ; i ++){
            if(s[i] == '#'){
                if(!tmps.empty()) tmps.pop_back();
            } 
            else tmps.push_back(s[i]);
        }
        for(int i = 0 ; i < t.size() ; i ++){
            if(t[i] == '#'){
                if(!tmpt.empty()) tmpt.pop_back();
            } 
            else tmpt.push_back(t[i]);
        }
        if(tmps.size() != tmpt.size()) return false;
        for(int i = 0 ; i < tmps.size() ; i ++){
            if(tmps[i] != tmpt[i]) return false;
        }
        return true;
    }
};

也可以用栈实现。

  • 双指针
class Solution {
public:
    bool backspaceCompare(string S, string T) {
        int i = S.length() - 1, j = T.length() - 1;
        int skipS = 0, skipT = 0;

        while (i >= 0 || j >= 0) {
            while (i >= 0) {
                if (S[i] == '#') {skipS++, i--;}
                else if (skipS > 0) {skipS--, i--;} 
                else break;                
            }
            while (j >= 0) {
                if (T[j] == '#') {skipT++, j--;}
                else if (skipT > 0) {skipT--, j--;} 
                else break;
            }
            if (i >= 0 && j >= 0) {
                if (S[i] != T[j]) {
                    return false;
                }
            } else {
                if (i >= 0 || j >= 0) {
                    return false;
                }
            }
            i--, j--;
        }
        return true;
    }
};

理论上时间和第一种都是 O( M + N ) ,而空间第一种 O ( M + N ),第二种 O( 1 ) 。
然而实际上运算结果空间的占用情况两者没有差异。

lc.986 区间列表的交集

给定两个由一些 闭区间 组成的列表,firstList 和 secondList ,其中 firstList[i] = [starti, endi] 而 secondList[j] = [startj, endj] 。每个区间列表都是成对 不相交 的,并且 已经排序 。
返回这 两个区间列表的交集 。
形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b 。
两个闭区间的 交集 是一组实数,要么为空集,要么为闭区间。例如,[1, 3] 和 [2, 4] 的交集为 [2, 3] 。

  • 归并
class Solution {
public:
    vector<vector<int>> intervalIntersection(vector<vector<int>>& firstList, vector<vector<int>>& secondList) {
        vector<vector<int>> ans;
        vector<int> tmp;
        int vi = 0 , vj = 0 ;
        while(vi < firstList.size() && vj < secondList.size()){
            int fb = firstList[vi][0], sb = secondList[vj][0], fe = firstList[vi][1], se = secondList[vj][1];
            tmp.emplace_back(max(fb,sb));
            tmp.emplace_back(min(fe,se));
            if(tmp[0] <= tmp[1]) {
                ans.emplace_back(tmp);
                tmp.clear();
            }
            if(fe < se) vi ++;
            else vj ++;
            tmp.clear();
        }
        return ans;    
    }
};

只需要判断每个区间的尾巴就好,比头小一定比尾巴小。智慧的光辉在闪烁。

lc.11 盛最多水的容器

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。

  • 双指针
class Solution {
public:
    int maxArea(vector<int>& height) {
        int l = 0 , r = (int)height.size() - 1;
        int ans = 0 , tmp = 0;
        while(l < r){
            tmp = (r - l) * min(height[l] , height[r]);
            ans = max(ans , tmp);
            if(height[l] < height[r]) l ++;
            else r --;
        }
        return ans;
    }
};

滑动窗口

lc.713 乘积小于k的子数组

给定一个正整数数组 nums和整数 k 。
请找出该数组内乘积小于 k 的连续的子数组的个数。

  • 遍历 + 滑动
class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        int n = nums.size() , cnt = 0 ;
        int allpro = (1 + n) * n / 2; 
        if(n == 1){
            if(nums[0] < k) return 1;
            else return 0;
        }
        for(int i = 0 ; i < n ; i ++){
            int j = i + 1 , pro = nums[i] ;
            if(nums[i] >= k){
                cnt += n - i ;
                continue;
            }
            while(j < n){
                pro *= nums[j];
                if(pro >= k){
                    cnt += n - j ;
                    break;
                }
                j ++;
            }
        }
        return allpro - cnt;
    }
};

在这里插入图片描述

  • 滑动窗口
class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
       if (k <= 1) return 0;
        int prod = 1, ans = 0, left = 0;
        for (int right = 0; right < nums.size(); right++) {
            prod *= nums[right];
            while (prod >= k) prod /= nums[left++];
            ans += right - left + 1;
        }
        return ans;
    }
};

lc.209 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

  • 滑动窗口 + 一堆倒霉的边界条件
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size() ; 
        if(n == 1) {
            if(nums[0] >= target) return 1;
            else return 0 ;
        }
        if(nums[0] >= target) return 1;
        int l = 0 , r = 1 , sum = nums[0] + nums[1] , ans = n + 1;
        while(r < n && l <= r){
            if(sum < target){
                if(r == n - 1) break;
                r ++;
                sum += nums[r];
            }
            else{
                ans = min(ans , r - l + 1);
                sum -= nums[l];
                l ++;
            }
        }
        if(ans < n + 1) return ans;
        else return 0 ;
    }
};

DFS/BFS

lc.200 岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

  • DFS
class Solution {
public:
    void dfs(vector<vector<char>>& grid , int i , int j){
        int m = grid.size() , n = grid[0].size();
        grid[i][j] = '0';
        if(i + 1 < m && grid[i + 1][j] == '1') dfs(grid, i + 1 , j);
        if(i - 1 > -1 && grid[i - 1][j] == '1') dfs(grid, i - 1 , j);
        if(j + 1 < n && grid[i][j + 1] == '1') dfs(grid, i , j + 1);
        if(j - 1 > -1 && grid[i][j - 1] == '1') dfs(grid, i , j - 1);
    }
    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size() , n = grid[0].size();
        if(m == 0) return 0 ;
        int cnt = 0 ;
        for(int i = 0 ; i < m ; i ++){
            for(int j = 0 ; j < n ; j ++){
                if(grid[i][j] == '1'){
                    cnt ++;
                    dfs(grid , i , j);
                }
            }
        }
        return cnt;
    }
};

每一个点都搜一遍,如果是 ‘1’ 就 DFS 一下,并且全变成 ‘0’ 。

  • BFS
class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size() , n = grid[0].size();
        if(m == 0) return 0 ;
        int cnt = 0 ;
        for(int i = 0 ; i < m ; i ++){
            for(int j = 0 ; j < n ; j ++){
                if(grid[i][j] == '1'){
                    cnt ++;
                    grid[i][j] = '0';
                    queue<pair<int,int>> isL;
                    isL.push({i,j});
                    while(!isL.empty()){
                        auto tmp = isL.front();
                        isL.pop();
                        int x = tmp.first , y = tmp.second;
                        if(x + 1 < m && grid[x + 1][y] == '1') {
                            isL.push({x + 1 , y}); grid[x + 1][y] = '0';
                        }
                        if(x - 1 > -1 && grid[x - 1][y] == '1'){
                            isL.push({x - 1 , y}); grid[x - 1][y] = '0';
                        } 
                        if(y + 1 < n && grid[x][y + 1] == '1'){
                            isL.push({x , y + 1}); grid[x][y + 1] = '0';
                        } 
                        if(y - 1 > -1 && grid[x][y - 1] == '1'){
                            isL.push({x , y - 1}); grid[x][y - 1] = '0';
                        } 
                    }
                }
            }
        }
        return cnt;
    }
};

用 queue 实现 , 注意写法queue<pair<int,int>> isL;int x = tmp.first , y = tmp.second;

  • 并查集
class UnionFind {
public:
    UnionFind(vector<vector<char>>& grid) {
        count = 0;
        int m = grid.size();
        int n = grid[0].size();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == '1') {
                    parent.push_back(i * n + j);
                    ++count;
                }
                else {
                    parent.push_back(-1);
                }
                rank.push_back(0);
            }
        }
    }

    int find(int i) {
        if (parent[i] != i) {
            parent[i] = find(parent[i]);
        }
        return parent[i];
    }

    void unite(int x, int y) {
        int rootx = find(x);
        int rooty = find(y);
        if (rootx != rooty) {
            if (rank[rootx] < rank[rooty]) {
                swap(rootx, rooty);
            }
            parent[rooty] = rootx;
            if (rank[rootx] == rank[rooty]) rank[rootx] += 1;
            --count;
        }
    }

    int getCount() const {
        return count;
    }

private:
    vector<int> parent;
    vector<int> rank;
    int count;
};

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int nr = grid.size();
        if (!nr) return 0;
        int nc = grid[0].size();

        UnionFind uf(grid);
        int num_islands = 0;
        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                if (grid[r][c] == '1') {
                    grid[r][c] = '0';
                    if (r - 1 >= 0 && grid[r-1][c] == '1') uf.unite(r * nc + c, (r-1) * nc + c);
                    if (r + 1 < nr && grid[r+1][c] == '1') uf.unite(r * nc + c, (r+1) * nc + c);
                    if (c - 1 >= 0 && grid[r][c-1] == '1') uf.unite(r * nc + c, r * nc + c - 1);
                    if (c + 1 < nc && grid[r][c+1] == '1') uf.unite(r * nc + c, r * nc + c + 1);
                }
            }
        }

        return uf.getCount();
    }
};

lc.547 省份数量

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

返回矩阵中 省份 的数量。

  • BFS
class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        int n = isConnected.size() , cnt = 0 ;
        vector<int> city(n,0);
        queue<int> que;
        for(int i = 0 ; i < n ; i ++){
            if(city[i] == 0){
               que.push(i);
               city[i] = 1;
               while(!que.empty()){
                   auto x = que.front();
                   que.pop();
                   for(int j = 0 ; j < n ; j ++){
                       if(isConnected[x][j] == 1 && city[j] == 0){
                           que.push(j);
                           city[j] = 1;
                       } 
                   }
               }
               cnt ++;
            }
        }
    return cnt;
    }
};
  • DFS
class Solution {
public:
    void dfs(vector<vector<int>>& isConnected , int i , vector<int>& city){
        int n = isConnected.size();
        for(int j = 0 ; j < n ; j ++){
            if(isConnected[i][j] == 1 && city[j] == 0){
                city[j] = 1;
                dfs(isConnected , j , city);
            }
        }
    }
    int findCircleNum(vector<vector<int>>& isConnected) {
        int n = isConnected.size() , cnt = 0 ;
        vector<int> city(n,0);
        for(int i = 0 ; i < n ; i ++){
            if(city[i] == 0){
               dfs(isConnected , i , city);
               cnt ++;
            }
        }
    return cnt;
    }
};

lc.117 填充每个节点的下一个右侧结点 II

给定一个二叉树
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;
    Node* next;

    Node() : val(0), left(NULL), right(NULL), next(NULL) {}

    Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

    Node(int _val, Node* _left, Node* _right, Node* _next)
        : val(_val), left(_left), right(_right), next(_next) {}
};
*/

class Solution {
public:
    Node* connect(Node* root) {
        if (!root) {
            return nullptr;
        }
        queue<Node*> q;
        q.push(root);
        while (!q.empty()) {
            int n = q.size();
            Node *last = nullptr;
            for (int i = 1; i <= n; ++i) {
                Node *f = q.front();
                q.pop();
                if (f->left) {
                    q.push(f->left);
                }
                if (f->right) {
                    q.push(f->right);
                }
                if (i != 1) {
                    last->next = f;
                }
                last = f;
            }
        }
        return root;
    }
};

lc.572 另一棵树的子数

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    static constexpr int MAX_N = 1000 + 5;
    static constexpr int MOD = int(1E9) + 7;

    bool vis[MAX_N];
    int p[MAX_N], tot;
    void getPrime() {
        vis[0] = vis[1] = 1; tot = 0;
        for (int i = 2; i < MAX_N; ++i) {
            if (!vis[i]) p[++tot] = i;
            for (int j = 1; j <= tot && i * p[j] < MAX_N; ++j) {
                vis[i * p[j]] = 1;
                if (i % p[j] == 0) break;
            }
        }
    }

    struct Status {
        int f, s; // f 为哈希值 | s 为子树大小
        Status(int f_ = 0, int s_ = 0) 
            : f(f_), s(s_) {}
    };

    unordered_map <TreeNode *, Status> hS, hT;

    void dfs(TreeNode *o, unordered_map <TreeNode *, Status> &h) {
        h[o] = Status(o->val, 1);
        if (!o->left && !o->right) return;
        if (o->left) {
            dfs(o->left, h);
            h[o].s += h[o->left].s;
            h[o].f = (h[o].f + (31LL * h[o->left].f * p[h[o->left].s]) % MOD) % MOD;
        }
        if (o->right) {
            dfs(o->right, h);
            h[o].s += h[o->right].s;
            h[o].f = (h[o].f + (179LL * h[o->right].f * p[h[o->right].s]) % MOD) % MOD;
        }
    }

    bool isSubtree(TreeNode* s, TreeNode* t) {
        getPrime();
        dfs(s, hS);
        dfs(t, hT);

        int tHash = hT[t].f;
        for (const auto &[k, v]: hS) {
            if (v.f == tHash) {
                return true;
            }
        } 

        return false;
    }
};

lc.1091 二进制矩阵中的最短路径

给你一个 n x n 的二进制矩阵 grid 中,返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径,返回 -1 。
二进制矩阵中的 畅通路径 是一条从 左上角 单元格(即,(0, 0))到 右下角 单元格(即,(n - 1, n - 1))的路径,该路径同时满足下述要求:

路径途经的所有单元格都的值都是 0 。
路径中所有相邻的单元格应当在 8 个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。

畅通路径的长度 是该路径途经的单元格总数。

  • BFS wrong ans
class Solution {
public:
    int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
        vector<vector<int>> direction = {{0,1} , {-1,1} , {1,0} , {1,-1} , {0,-1} , {-1,-1} , {-1,0} , {1,1}};
        int step = 1 , n = grid.size();
        if(n == 0) return -1;
        if(grid[0][0] == 1 || grid[n - 1][n - 1] == 1) return -1; 
        queue<pair<int,int>> que;
        que.push( {0,0} );
        grid[0][0] == 1;
        while(!que.empty()){
            int Times = que.size() ;
            while(Times > 0){
                auto tmp = que.front();
                que.pop();
                int x = tmp.first , y = tmp.second ;     
                for(int i = 0 ; i < 8 ; i ++){
                    int nextx = x + direction[i][0] , nexty = y + direction[i][1];
                    if(nextx < 0 || nextx >= n || nexty < 0 || nexty >= n || grid[nextx][nexty] == 1) 
                        continue;
                    que.push({nextx,nexty});
                    grid[nextx][nexty] = 1;
                }
                Times --;
            }            
            step ++ ;
            if(grid[n - 1][n - 1] == 1) return step;            
        }
        return -1;
    }
};

判断语句 if(grid[n - 1][n - 1] == 1) return step; 使得测试用例 [[0]] 无法通过。

  • BFS
class Solution {
public:
    int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
        vector<vector<int>> direction = {{0,1} , {-1,1} , {1,0} , {1,-1} , {0,-1} , {-1,-1} , {-1,0} , {1,1}};
        int step = 1 , n = grid.size();
        if(n == 0) return -1;
        if(grid[0][0] == 1 || grid[n - 1][n - 1] == 1) return -1; 
        queue<pair<int,int>> que;
        que.push( {0,0} );
        while(!que.empty()){
            int Times = que.size() ;
            while(Times > 0){
                auto tmp = que.front();
                que.pop();
                int x = tmp.first , y = tmp.second ;
                if(x == n - 1 && y == n - 1) return step;
                for(int i = 0 ; i < 8 ; i ++){
                    int nextx = x + direction[i][0] , nexty = y + direction[i][1];
                    if(nextx >= 0 && nextx < n && nexty >= 0 && nexty < n && grid[nextx][nexty] == 0){
                        que.push({nextx , nexty});
                        grid[nextx][nexty] = 1;
                    }
                }
                Times --;
            }
            step ++ ;
            
        }
        return -1;
    }
};

lc.130 被围绕的区域

给你一个 m x n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。

  • BFS wrong ans
class Solution {
public:
    void solve(vector<vector<char>>& board) {
        vector<vector<int>> direction = {{0,1},{0,-1},{1,0},{-1,0}};
        queue<pair<int , int>> que ;
        int m = board.size() , n = board[0].size() ;
        if(m <= 2 || n <= 2) return ;
        for(int i = 1 ; i < m - 1 ; i ++){
            for(int j = 1 ; j < n - 1 ; j ++){
                if(board[i][j] == 'O'){
                    board[i][j] = 'X';
                    que.push({i,j});
                    while(!que.empty()){
                        auto tmp = que.front();
                        que.pop();
                        int x = tmp.first , y = tmp.second ;
                        for(int pre = 0 ; pre < 4 ; pre ++){
                            int nx = x + direction[pre][0] , ny = y + direction[pre][1];
                            if(nx > 0 && nx < m - 1 && ny > 0 && ny < n - 1 && board[nx][ny] == 'O'){
                                board[nx][ny] = 'X';
                                que.push({nx,ny});
                            }
                        }
                    }

                }
            }
        }
        return ;
    }
};

在这里插入图片描述
没考虑到第一个位置的合理性。

  • BFS
class Solution {
public:
    const int dx[4] = {1, -1, 0, 0};
    const int dy[4] = {0, 0, 1, -1};

    void solve(vector<vector<char>>& board) {
        int n = board.size();
        if (n == 0) {
            return;
        }
        int m = board[0].size();
        queue<pair<int, int>> que;
        for (int i = 0; i < n; i++) {
            if (board[i][0] == 'O') {
                que.emplace(i, 0);
                board[i][0] = 'A';
            }
            if (board[i][m - 1] == 'O') {
                que.emplace(i, m - 1);
                board[i][m - 1] = 'A';
            }
        }
        for (int i = 1; i < m - 1; i++) {
            if (board[0][i] == 'O') {
                que.emplace(0, i);
                board[0][i] = 'A';
            }
            if (board[n - 1][i] == 'O') {
                que.emplace(n - 1, i);
                board[n - 1][i] = 'A';
            }
        }
        while (!que.empty()) {
            int x = que.front().first, y = que.front().second;
            que.pop();
            for (int i = 0; i < 4; i++) {
                int mx = x + dx[i], my = y + dy[i];
                if (mx < 0 || my < 0 || mx >= n || my >= m || board[mx][my] != 'O') {
                    continue;
                }
                que.emplace(mx, my);
                board[mx][my] = 'A';
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (board[i][j] == 'A') {
                    board[i][j] = 'O';
                } else if (board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
            }
        }
    }
};

直接对每个边上的‘O’搜索,如果搜到了都保持原状,其余的全成‘X’。

  • DFS
class Solution {
public:
    int n, m;

    void dfs(vector<vector<char>>& board, int x, int y) {
        if (x < 0 || x >= n || y < 0 || y >= m || board[x][y] != 'O') {
            return;
        }
        board[x][y] = 'A';
        dfs(board, x + 1, y);
        dfs(board, x - 1, y);
        dfs(board, x, y + 1);
        dfs(board, x, y - 1);
    }

    void solve(vector<vector<char>>& board) {
        n = board.size();
        if (n == 0) {
            return;
        }
        m = board[0].size();
        for (int i = 0; i < n; i++) {
            dfs(board, i, 0);
            dfs(board, i, m - 1);
        }
        for (int i = 1; i < m - 1; i++) {
            dfs(board, 0, i);
            dfs(board, n - 1, i);
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (board[i][j] == 'A') {
                    board[i][j] = 'O';
                } else if (board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
            }
        }
    }
};

lc.797 所有可能的路径

给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序)

graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。

  • DFS wrong ans
class Solution {
public:
    void dfs(int i , vector<int>& tmp , vector<vector<int>>& ans , vector<vector<int>>& graph) {
        if(graph[i].size() == 0){
            tmp.emplace_back(i);
            ans.emplace_back(tmp);
            tmp.pop_back();
            return;
        }
        tmp.emplace_back(i);
        for(int j = 0 ; j < graph[i].size() ; j ++){            
            dfs(graph[i][j] , tmp , ans , graph);
        }
        tmp.pop_back();
    }
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
        vector<vector<int>> ans;
        vector<int> tmp;
        dfs(0 , tmp , ans , graph);
        return ans;
    }
};

题目要求结尾是 n - 1 。

  • DFS wrong ans
class Solution {
public:
    void dfs(int i , vector<int>& tmp , vector<vector<int>>& ans , vector<vector<int>>& graph) {
        if(graph[i].size() == 0 && i == graph.size() - 1){
            tmp.emplace_back(i);
            ans.emplace_back(tmp);
            tmp.pop_back();
            return;
        }
        tmp.emplace_back(i);
        for(int j = 0 ; j < graph[i].size() ; j ++){            
            dfs(graph[i][j] , tmp , ans , graph);
        }
        tmp.pop_back();
    }
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
        vector<vector<int>> ans;
        vector<int> tmp;
        dfs(0 , tmp , ans , graph);
        return ans;
    }
};

在这里插入图片描述

服了。到 n - 1 就截止了,后面不搜了。

  • DFS
class Solution {
public:
    void dfs(int i , vector<int>& tmp , vector<vector<int>>& ans , vector<vector<int>>& graph) {
        if(i == graph.size() - 1){
            tmp.emplace_back(i);
            ans.emplace_back(tmp);
            tmp.pop_back();
            return;
        }
        tmp.emplace_back(i);
        for(int j = 0 ; j < graph[i].size() ; j ++){            
            dfs(graph[i][j] , tmp , ans , graph);
        }
        tmp.pop_back();
    }
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
        vector<vector<int>> ans;
        vector<int> tmp;
        dfs(0 , tmp , ans , graph);
        return ans;
    }
};

读懂题意还是很重要的。wdnmd。

递归与回溯

lc.78 子集 全组合

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

  • DFS
class Solution {
public:
    bool is[11] = {0};
    void dfs(int x , vector<int>& nums , vector<int>& tmp , vector<vector<int>>& ans){
        ans.emplace_back(tmp);
        for(int i = x ; i < nums.size() ; i ++){
            if(!is[i]){
                is[i] = true ;  
                tmp.emplace_back(nums[i]);
                dfs(i + 1 , nums , tmp , ans);
                is[i] = false ;
                tmp.pop_back();
            }
        }
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> ans;
        vector<int> tmp;
        dfs(0 , nums , tmp , ans);
        return ans;
    }
};

lc.90 子集II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

  • DFS lc.78基础上剪枝
class Solution {
public:
    bool is[11] = {0};
    void dfs(int x , vector<int>& nums , vector<int>& tmp , vector<vector<int>>& ans){
        ans.emplace_back(tmp);
        for(int i = x ; i < nums.size() ; i ++){
            if(i > 0 && nums[i - 1] == nums[i] && is[i - 1] == false) continue;
            if(!is[i]){
                is[i] = true ;  
                tmp.emplace_back(nums[i]);
                dfs(i + 1 , nums , tmp , ans);
                is[i] = false ;
                tmp.pop_back();
            }
        }
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<vector<int>> ans;
        vector<int> tmp;
        sort(nums.begin(),nums.end());
        dfs(0 , nums , tmp , ans);
        return ans;
    }
};

if(i > 0 && nums[i - 1] == nums[i] && is[i - 1] == false) continue; 剪枝。
注意到不同于排列,组合不考虑所有的顺序,所以需要先 sort 一下。

lc.39 组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。

class Solution {
public:
    void dfs(vector<int>& candidates, int target, vector<vector<int>>& ans, vector<int>& combine, int idx) {
        if (idx == candidates.size()) {
            return;
        }
        if (target == 0) {
            ans.emplace_back(combine);
            return;
        }
        // 直接跳过
        dfs(candidates, target, ans, combine, idx + 1);
        // 选择当前数
        if (target - candidates[idx] >= 0) {
            combine.emplace_back(candidates[idx]);
            dfs(candidates, target - candidates[idx], ans, combine, idx);
            combine.pop_back();
        }
    }

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> ans;
        vector<int> combine;
        dfs(candidates, target, ans, combine, 0);
        return ans;
    }
};

lc.40 组合总和 II

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。

class Solution {
private:
    vector<pair<int, int>> freq;
    vector<vector<int>> ans;
    vector<int> sequence;

public:
    void dfs(int pos, int rest) {
        if (rest == 0) {
            ans.push_back(sequence);
            return;
        }
        if (pos == freq.size() || rest < freq[pos].first) {
            return;
        }

        dfs(pos + 1, rest);

        int most = min(rest / freq[pos].first, freq[pos].second);
        for (int i = 1; i <= most; ++i) {
            sequence.push_back(freq[pos].first);
            dfs(pos + 1, rest - i * freq[pos].first);
        }
        for (int i = 1; i <= most; ++i) {
            sequence.pop_back();
        }
    }

    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        for (int num: candidates) {
            if (freq.empty() || num != freq.back().first) {
                freq.emplace_back(num, 1);
            } else {
                ++freq.back().second;
            }
        }
        dfs(0, target);
        return ans;
    }
};

lc.17 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

  • DFS(也不知道对不对,debug开头就有问题)
class Solution {
public:
    vector<vector<string>> ex = {{},{},{"a","b","c"},{"d","e","f"},{"g","h","i"},{"j","k","l"},{"m","n","o"},{"p","q","r","s"},{"t","u","v"},{"w","x","y","z"}};
    void dfs(string tmp, vector<string>& ans, string digits, int x){
        if(x == digits.size()){
            ans.emplace_back(tmp);
            return ;
        }
        for(int i = 0 ; i < ex[x].size() ; i ++){
            tmp += ex[x][i];
            dfs(tmp, ans, digits, x + 1);
            tmp.pop_back();
        }

    }
    vector<string> letterCombinations(string digits) {
        vector<string> ans;
        string tmp = "";
        dfs(tmp, ans, digits, 0);
        return ans;
    }
};

这是什么情况···不管输入什么测试用例结局都是直接返回空。
在这里插入图片描述

我是蠢货,x 是 digits 的下标,不是 ex 的下标。
上图是运行到此的数值,再往下运行一步, n = 2 了。

  • 0ms
class Solution {
public:
    vector<vector<string>> ex = {{},{},{"a","b","c"},{"d","e","f"},{"g","h","i"},{"j","k","l"},{"m","n","o"},{"p","q","r","s"},{"t","u","v"},{"w","x","y","z"}};
    void dfs(string tmp, vector<string>& ans, string digits, int x){
        if(x == digits.size()){
            ans.emplace_back(tmp);
            return ;
        }
        int n = digits[x] - '0';
        for(int i = 0 ; i < ex[n].size() ; i ++){
            tmp += ex[n][i];
            dfs(tmp, ans, digits, x + 1);
            tmp.pop_back();
        }

    }
    vector<string> letterCombinations(string digits) {
        vector<string> ans;
        if(digits.size() == 0) return ans;
        string tmp = "";
        int n = digits.size();
        dfs(tmp, ans, digits, 0);
        return ans;
    }
};
  • 回溯
class Solution {
public:
    vector<string> letterCombinations(string digits) {
        vector<string> combinations;
        int n = (int)digits.length();
        if (digits.empty()) {
            return combinations;
        }
        unordered_map<char, string> phoneMap{
            {'2', "abc"},
            {'3', "def"},
            {'4', "ghi"},
            {'5', "jkl"},
            {'6', "mno"},
            {'7', "pqrs"},
            {'8', "tuv"},
            {'9', "wxyz"}
        };
        string combination;
        backtrack(combinations, phoneMap, digits, 0, combination);
        return combinations;
    }

    void backtrack(vector<string>& combinations, const unordered_map<char, string>& phoneMap, const string& digits, int index, string& combination) {
        if (index == digits.length()) {
            combinations.push_back(combination);
        } else {
            char digit = digits[index];
            const string& letters = phoneMap.at(digit);
            for (const char& letter: letters) {
                combination.push_back(letter);
                backtrack(combinations, phoneMap, digits, index + 1, combination);
                combination.pop_back();
            }
        }
    }
};

题解length的调用就没有问题。

lc.22 括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

  • DFS
class Solution {
public:
    void dfs(string tmp, vector<string>& ans, int n, int countleft, int countright){
        if(countleft == n && countright == n){
            ans.emplace_back(tmp);
            return ;
        }
        if(countleft < n){
            tmp += "(" ;
            dfs(tmp, ans, n, countleft + 1 , countright);
            tmp.pop_back();
        }
        if(countright < n && countright < countleft){
            tmp += ")" ;
            dfs(tmp, ans, n, countleft , countright + 1);
            tmp.pop_back();
        }
    }
    vector<string> generateParenthesis(int n) {
        string tmp ;
        vector<string> ans;
        int countleft = 0 , countright = 0 ;
        dfs(tmp, ans, n, countleft, countright);
        return ans;
    }
};

越写越快,只要理清条件,只能说轻轻松松。

lc.79 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

  • BFS WRONG
class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        vector<vector<int>> direction = {{0,1},{0,-1},{1,0},{-1,0}};
        queue<pair<int,int>> que;
        int m = board.size() , n = board[0].size();
        for(int i = 0 ; i < m ; i ++){
            for(int j = 0 ; j < n ; j ++){
                bool isVisited[m][n] = {0};
                int iword = 0 ;
                char tmpa = board[i][j] , tmpb = word[iword];
                if(board[i][j] == word[iword]){
                    que.push({i,j});
                    isVisited[i][j] = true;
                    iword ++;
                    while(!que.empty()){
                        int times = que.size();
                        while(times > 0){
                            auto tmp = que.front(); que.pop();
                            int x = tmp.first , y = tmp.second ;
                            isVisited[x][y] = true;
                            for(int i = 0 ; i < 4 ; i ++){
                                int prex = x + direction[i][0] , prey = y + direction[i][1];
                                if(prex >= 0 && prex < m && prey >= 0 && prey < n && board[prex][prey] == word[iword] && isVisited[prex][prey] == false){
                                    que.push({prex,prey});
                                }
                            }
                            times --;
                        }
                        iword ++ ;
                    }
                    if(iword == word.size() + 1) return true;
                }
            }
        }
        return false;
    }
};

一眼看上去是一个 BFS 的问题,然而假如是这样一个情况:

请添加图片描述

但是如果不开 bool 数组记录是否走过,就会往回搜索,造成错误。

  • 虽然DFS回溯对于这种图来说很慢,但是这题不得不这样做
class Solution {
public:
    bool check(vector<vector<char>>& board, vector<vector<int>>& visited, int i, int j, string& s, int k) {
        if (board[i][j] != s[k]) {
            return false;
        } else if (k == s.length() - 1) {
            return true;
        }
        visited[i][j] = true;
        vector<pair<int, int>> directions{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        bool result = false;
        for (const auto& dir: directions) {
            int newi = i + dir.first, newj = j + dir.second;
            if (newi >= 0 && newi < board.size() && newj >= 0 && newj < board[0].size()) {
                if (!visited[newi][newj]) {
                    bool flag = check(board, visited, newi, newj, s, k + 1);
                    if (flag) {
                        result = true;
                        break;
                    }
                }
            }
        }
        visited[i][j] = false;
        return result;
    }

    bool exist(vector<vector<char>>& board, string word) {
        int h = board.size(), w = board[0].size();
        vector<vector<int>> visited(h, vector<int>(w));
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                bool flag = check(board, visited, i, j, word, 0);
                if (flag) {
                    return true;
                }
            }
        }
        return false;
    }
};
  • 最快的剪枝
class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        int m = board.size(), n = board[0].size();
        vector<int> cnt(128, 0);
        for (auto c : word) 
            ++cnt[c];

        if (cnt[word[0]] > cnt[word[word.size()-1]])    reverse(word.begin(), word.end());

        for (auto v : board)
            for (auto c : v)
                --cnt[c];

        for (int i = 0; i < 128; ++i)
            if (cnt[i] > 0) return false;
        
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (board[i][j] == word[0] && dfs(board, word, 0, i, j)) {
                    return true;
                }
            }
        }
        return false;
    }
    bool dfs(vector<vector<char>>& m, string s, int idx, int x, int y) {
        if (x < 0 || x >= m.size() || y < 0 || y >= m[0].size() || m[x][y] != s[idx])   return false;
        if (++idx == s.size())  return true;
        
        m[x][y] += 128;
        if (dfs(m, s, idx, x, y+1)) return true;
        if (dfs(m, s, idx, x, y-1)) return true;
        if (dfs(m, s, idx, x-1, y)) return true;
        if (dfs(m, s, idx, x+1, y)) return true;
        m[x][y] -= 128;

        return false;;
    }
};

这居然 0ms 。

位运算

lc.201 数字范围按位与

给你两个整数 left 和 right ,表示区间 [left, right] ,返回此区间内所有数字 按位与 的结果(包含 left 、right 端点)。

ELSE

lc.384 打乱数组

给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。打乱后,数组的所有排列应该是 等可能 的。

实现 Solution class:

Solution(int[] nums) 使用整数数组 nums 初始化对象
int[] reset() 重设数组到它的初始状态并返回
int[] shuffle() 返回数组随机打乱后的结果
class Solution {
public:
    Solution(vector<int>& nums) {
        this->nums = nums;
        this->original.resize(nums.size());
        copy(nums.begin(), nums.end(), original.begin());
    }
    
    vector<int> reset() {
        copy(original.begin(), original.end(), nums.begin());
        return nums;
    }
    
    vector<int> shuffle() {
        for (int i = 0; i < nums.size(); ++i) {
            int j = i + rand() % (nums.size() - i);
            swap(nums[i], nums[j]);
        }
        return nums;
    }
private:
    vector<int> nums;
    vector<int> original;
};

lc.149 直线上最多的点数

给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。

class Solution {
public:
    int gcd(int a, int b) {
        return b ? gcd(b, a % b) : a;
    }

    int maxPoints(vector<vector<int>>& points) {
        int n = points.size();
        if (n <= 2) {
            return n;
        }
        int ret = 0;
        for (int i = 0; i < n; i++) {
            if (ret >= n - i || ret > n / 2) {
                break;
            }
            unordered_map<int, int> mp;
            for (int j = i + 1; j < n; j++) {
                int x = points[i][0] - points[j][0];
                int y = points[i][1] - points[j][1];
                if (x == 0) {
                    y = 1;
                } else if (y == 0) {
                    x = 1;
                } else {
                    if (y < 0) {
                        x = -x;
                        y = -y;
                    }
                    int gcdXY = gcd(abs(x), abs(y));
                    x /= gcdXY, y /= gcdXY;
                }
                mp[y + x * 20001]++;
            }
            int maxn = 0;
            for (auto& [_, num] : mp) {
                maxn = max(maxn, num + 1);
            }
            ret = max(ret, maxn);
        }
        return ret;
    }
};
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值