2022-6-13 全O(1)的数据结构,两数相加,无重复字符的最长子串,寻找两个正序数组的中位数,盛最多水的容器,......

1. 全 O(1) 的数据结构

Design a data structure to store the strings’ count with the ability to return the strings with minimum and maximum counts.

Implement the AllOne class:

  • AllOne() Initializes the object of the data structure.
  • inc(String key) Increments the count of the string key by 1. If key does not exist in the data structure, insert it with count 1.
  • dec(String key) Decrements the count of the string key by 1. If the count of key is 0 after the decrement, remove it from the data structure. It is guaranteed that key exists in the data structure before the decrement.
  • getMaxKey() Returns one of the keys with the maximal count. If no element exists, return an empty string "".
  • getMinKey() Returns one of the keys with the minimum count. If no element exists, return an empty string "".

Note that each function must run in O(1) average time complexity.

Example 1

Input
["AllOne", "inc", "inc", "getMaxKey", "getMinKey", "inc", "getMaxKey", "getMinKey"]
[[], ["hello"], ["hello"], [], [], ["leet"], [], []]
Output
[null, null, null, "hello", "hello", null, "hello", "leet"]

Explanation
AllOne allOne = new AllOne();
allOne.inc("hello");
allOne.inc("hello");
allOne.getMaxKey(); // return "hello"
allOne.getMinKey(); // return "hello"
allOne.inc("leet");
allOne.getMaxKey(); // return "hello"
allOne.getMinKey(); // return "leet"

Constraints:

  • 1 <= key.length <= 10
  • key consists of lowercase English letters.
  • It is guaranteed that for each call to dec, key is existing in the data structure.
  • At most 5 * 10^4 calls will be made to inc, dec, getMaxKey, and getMinKey.

代码 [双向链表/哈希]

struct Node {
    string s;
    int val;
    Node *prev, *next;
    Node(string s, int val) : s(s), val(val), prev(nullptr), next(nullptr) {}
};

class AllOne {
private:
    unordered_map<string, Node *> mp;
    Node *dummyHead, *dummyTail;

    inline void insertNode(Node *node, Node *nodePrev, Node *nodeNext) {
        node->next = nodeNext, node->prev = nodePrev;
        node->prev->next = node;
        node->next->prev = node;
    }

    inline void deleteNode(Node *node) {
        node->prev->next = node->next;
        node->next->prev = node->prev;
    }

    inline void moveNode(Node *node, Node *nodePrev, Node *nodeNext) {
        if (node == nodePrev || node == nodeNext) return;
        deleteNode(node);
        insertNode(node, nodePrev, nodeNext);
    }

public:
    AllOne() {
        dummyHead = new Node("", 0);
        dummyTail = new Node("", INT_MAX);
        dummyHead->next = dummyTail;
        dummyTail->prev = dummyHead;
    }

    void inc(string key) {
        if (!mp.count(key)) {
            auto node = new Node(key, 1);
            insertNode(node, dummyHead, dummyHead->next);
            mp[key] = node;
        } else {
            auto node = mp[key];
            ++node->val;
            auto nodeNext = node;
            while (nodeNext->next->val < node->val) nodeNext = nodeNext->next;
            moveNode(node, nodeNext, nodeNext->next);
        }
    }

    void dec(string key) {
        if (!mp.count(key)) return;
        auto node = mp[key];
        --node->val;
        if (node->val == 0) {
            deleteNode(node);
            mp.erase(key);
            return;
        }
        auto nodeNext = node;
        while (nodeNext->prev->val > node->val) nodeNext = nodeNext->prev;
        moveNode(node, nodeNext->prev, nodeNext);
    }

    string getMaxKey() { return dummyTail->prev->s; }

    string getMinKey() { return dummyHead->next->s; }
};

2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

Example 1

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.

Example 2

输入:l1 = [0], l2 = [0]
输出:[0]

提示:

  • 每个链表中的节点数在范围 [1, 100]
  • 0 <= Node.val <= 9
  • 题目数据保证列表表示的数字不含前导零

代码

class Solution {
public:
    ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
        ListNode *head = new ListNode();
        ListNode *node = head;
        int inc = 0, tmp;
        while (l1 || l2) {
            tmp = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + inc;
            node = node->next = new ListNode(tmp % 10);
            inc = tmp / 10;
            if (l1) l1 = l1->next;
            if (l2) l2 = l2->next;
        }
        if (inc) node->next = new ListNode(1);
        return head->next;
    }
};

3. 无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

Example 1

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

Example 2

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

提示:

  • 0 <= s.length <= 5 * 10^4
  • s 由英文字母、数字、符号和空格组成

代码 [滑动窗口]

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        bool check[128];
        memset(check, 0, sizeof check);
        int result = 0;
        for (int i = 0, j = 0; j < s.size(); ++j) {
            while (check[s[j]]) check[s[i++]] = false;
            check[s[j]] = true;
            result = max(result, j - i + 1);
        }
        return result;
    }
};

4. 寻找两个正序数组的中位数

给定两个大小分别为 mn 的正序(从小到大)数组 nums1nums2。请你找出并返回这两个正序数组的 中位数

算法的时间复杂度应该为 O(log (m+n))

Example 1

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

Example 2

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

Constraints:

  • nums1.length == m
  • nums2.length == n
  • 0 <= m <= 1000
  • 0 <= n <= 1000
  • 1 <= m + n <= 2000
  • -10^6 <= nums1[i], nums2[i] <= 10^6

代码 [官方题解,二分]

class Solution {
public:
    double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
        if (nums1.size() > nums2.size()) {
            return findMedianSortedArrays(nums2, nums1);
        }

        int m = nums1.size();
        int n = nums2.size();
        int left = 0, right = m;
        // median1:前一部分的最大值
        // median2:后一部分的最小值
        int median1 = 0, median2 = 0;

        while (left <= right) {
            // 前一部分包含 nums1[0 .. i-1] 和 nums2[0 .. j-1]
            // 后一部分包含 nums1[i .. m-1] 和 nums2[j .. n-1]
            int i = (left + right) / 2;
            int j = (m + n + 1) / 2 - i;

            // nums_im1, nums_i, nums_jm1, nums_j 分别表示 nums1[i-1], nums1[i], nums2[j-1], nums2[j]
            int nums_im1 = (i == 0 ? INT_MIN : nums1[i - 1]);
            int nums_i = (i == m ? INT_MAX : nums1[i]);
            int nums_jm1 = (j == 0 ? INT_MIN : nums2[j - 1]);
            int nums_j = (j == n ? INT_MAX : nums2[j]);

            if (nums_im1 <= nums_j) {
                median1 = max(nums_im1, nums_jm1);
                median2 = min(nums_i, nums_j);
                left = i + 1;
            } else {
                right = i - 1;
            }
        }

        return (m + n) % 2 == 0 ? (median1 + median2) / 2.0 : median1;
    }
};

5. 盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

**说明:**你不能倾斜容器。

Example 1

输入:[1,8,6,2,5,4,8,3,7]
输出:49 

Example 2

输入:height = [1,1]
输出:1

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 10^4

代码 [双指针]

class Solution {
public:
    int maxArea(vector<int> &height) {
        int l = 0, r = height.size() - 1;
        int ans = 0;
        while (l < r) {
            int area = min(height[l], height[r]) * (r - l);
            ans = max(ans, area);
            height[l] < height[r] ? ++l : --r;
        }
        return ans;
    }
};

6. 颜色分类

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,**原地**对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 012 分别表示红色、白色和蓝色。

必须在不使用库的sort函数的情况下解决这个问题。

Example 1

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

Example 2

输入:nums = [2,0,1]
输出:[0,1,2]

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i]012

代码 [双指针]

class Solution {
public:
    void sortColors(vector<int> &nums) {
        for (int i = 0, j = 0; j < nums.size(); ++j) {
            if (nums[j] == 0) swap(nums[i++], nums[j]);
        }
        for (int i = nums.size() - 1, j = nums.size() - 1; j >= 0; --j) {
            if (nums[j] == 2) swap(nums[i--], nums[j]);
        }
    }
};

7. 最大矩形

给定一个仅包含 01 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

Example 1

输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:6

Example 2

输入:matrix = []
输出:0

提示:

  • rows == matrix.length
  • cols == matrix[0].length
  • 1 <= row, cols <= 200
  • matrix[i][j]'0''1'

代码 [单调栈]

class Solution {
private:
    int largestRectangleArea(const vector<int> &heights) {
        stack<int> st;
        vector<int> minArgRight(heights.size(), heights.size());
        vector<int> minArgLeft(heights.size(), -1);
        for (int i = heights.size() - 1; i >= 0; --i) {
            while (!st.empty() && heights[st.top()] >= heights[i]) st.pop();
            if (!st.empty()) {
                minArgRight[i] = st.top();
            }
            st.push(i);
        }
        while (!st.empty()) st.pop();
        for (int i = 0; i < heights.size(); ++i) {
            while (!st.empty() && heights[st.top()] >= heights[i]) st.pop();
            if (!st.empty()) {
                minArgLeft[i] = st.top();
            }
            st.push(i);
        }
        int maxArea = 0;
        for (int i = 0, tmpArea; i < heights.size(); ++i) {
            tmpArea = heights[i] * (minArgRight[i] - minArgLeft[i] - 1);
            if (tmpArea > maxArea) maxArea = tmpArea;
        }
        return maxArea;
    }

public:
    int maximalRectangle(vector<vector<char>> &matrix) {
        int m = matrix.size(), n = matrix[0].size();
        vector<vector<int>> mat(m, vector<int>(n, 0));
        for (int j = 0; j < matrix[0].size(); ++j) mat[0][j] = matrix[0][j] == '1';
        for (int i = 1; i < matrix.size(); ++i) {
            for (int j = 0; j < matrix[0].size(); ++j) {
                if (matrix[i][j] == '1') mat[i][j] = 1 + mat[i - 1][j];
            }
        }
        int result = 0;
        for (auto &h :mat) result = max(result, largestRectangleArea(h));
        return result;
    }
};

8. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

Example 1

输入:n = 2
输出:2

Example 2

输入:n = 3
输出:3

提示:

  • 1 <= n <= 45

代码 [DP,斐波那契数]

class Solution {
public:
    int climbStairs(int n) {
        int f = 0, g = 1;
        while (n--) {
            g += f;
            f = g - f;
        }
        return g;
    }
};

9. 爬楼梯

给定一个包含非负整数的 *m* x *n* 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

**说明:**每次只能向下或者向右移动一步。

Example 1

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7

Example 2

输入:grid = [[1,2,3],[4,5,6]]
输出:12

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 200
  • 0 <= grid[i][j] <= 100

代码

class Solution {
public:
    int minPathSum(vector<vector<int>> &grid) {
        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[0].size(); ++j) {
                if (i == 0 && j == 0) continue;
                grid[i][j] += min(i > 0 ? grid[i - 1][j] : 4000000, j > 0 ? grid[i][j - 1] : 4000000);
            }
        }
        return grid.back().back();
    }
};

9. 三数之和

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

**注意:**答案中不可以包含重复的三元组。

Example 1

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

Example 2

输入:nums = []
输出:[]

提示:

  • 0 <= nums.length <= 3000
  • -105 <= nums[i] <= 10^5

代码 [双指针]

class Solution {
public:
    vector<vector<int>> threeSum(vector<int> &nums) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        for (int i = 0; i + 2 < nums.size(); ++i) {
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            int j = i + 1, k = nums.size() - 1;
            while (j < k) {
                if (nums[i] + nums[j] + nums[k] == 0) {
                    result.push_back({nums[i], nums[j], nums[k]});
                    while (++j < nums.size() && nums[j] == nums[j - 1]) continue;
                    while (--k > i && nums[k] == nums[k + 1]) continue;
                } else if (nums[i] + nums[j] + nums[k] < 0) {
                    while (++j < nums.size() && nums[j] == nums[j - 1]) continue;
                } else {
                    while (--k > i && nums[k] == nums[k + 1]) continue;
                }
            }
        }
        return result;
    }
};

10. 括号生成

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

Example 1

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

Example 2

输入:n = 1
输出:["()"]

提示:

  • 1 <= n <= 8

代码 [栈,回溯]

class Solution {
private:
    vector<string> result;
    string path;

    void dfs(int st, int left, int right) {
        if (left == 0 && right == 0) {
            result.emplace_back(path);
            return;
        }
        if (left > 0) {
            path.push_back('(');
            dfs(st + 1, left - 1, right);
            path.pop_back();
        }
        if (st > 0 && right > 0) {
            path.push_back(')');
            dfs(st - 1, left, right - 1);
            path.pop_back();
        }
    }

public:
    vector<string> generateParenthesis(int n) {
        result.clear();
        path.clear();
        dfs(0, n, n);
        return result;
    }
};

11. 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

Example 1

输入:m = 3, n = 7
输出:28

Example 2

输入:m = 3, n = 2
输出:3

提示:

  • 1 <= m, n <= 100
  • 题目数据保证答案小于等于 2 * 10^9

代码 [动态规划]

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m, vector<int>(n, 0));
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                dp[i][j] = i == 0 || j == 0 ? 1 : dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return dp[m - 1][n - 1];
    }
};

12. 字母异位词分组

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。

Example 1

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

Example 2

输入: strs = [""]
输出: [[""]]

提示:

  • 1 <= strs.length <= 10^4
  • 0 <= strs[i].length <= 100
  • strs[i] 仅包含小写字母

代码 [哈希]

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string> &strs) {
        map<string, vector<string>> mp;
        for (auto &s : strs) {
            string key = string(26, '0');
            for (auto c : s) ++key[c - 'a'];
            mp[key].emplace_back(s);
        }
        vector<vector<string>> res;
        for (const auto &e : mp) res.emplace_back(e.second);
        return res;
    }
};

13. 环形链表

Given head, the head of a linked list, determine if the linked list has a cycle in it.

There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail’s next pointer is connected to. Note that pos is not passed as a parameter.

Return true if there is a cycle in the linked list. Otherwise, return false.

Example 1

Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).

Example 2

Input: head = [1,2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 0th node.

提示:

  • The number of the nodes in the list is in the range [0, 104].
  • -105 <= Node.val <= 105
  • pos is -1 or a valid index in the linked-list.

代码

class Solution {
public:
    bool hasCycle(ListNode *head) {
        auto i = head, j = head;
        while (j && j->next) {
            i = i->next, j = j->next->next;
            if (i == j) return true;
        }
        return false;
    }
};

14. 二叉树展开为链表

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

Example 1

输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]

Example 2

输入:root = []
输出:[]

提示:

  • 树中结点数在范围 [0, 2000]
  • -100 <= Node.val <= 100

代码

class Solution {
public:
    void flatten(TreeNode *root) {
        if (!root) return;
        stack<TreeNode *> st;
        TreeNode *head = new TreeNode();
        TreeNode *prev = head, *cur;
        st.push(root);
        while (!st.empty()) {
            cur = st.top();
            st.pop();
            if (cur->right) st.push(cur->right);
            if (cur->left) st.push(cur->left);
            cur->left = nullptr;
            prev->right = cur;
            prev = cur;
        }
        root = head->right;
    }
};

15. 从前序与中序遍历序列构造二叉树

给定两个整数数组 preorderinorder ,其中 preorder 是二叉树的先序遍历inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

Example 1

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

Example 2

输入: preorder = [-1], inorder = [-1]
输出: [-1]

提示:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorderinorder无重复 元素
  • inorder 均出现在 preorder
  • preorder 保证 为二叉树的前序遍历序列
  • inorder 保证 为二叉树的中序遍历序列

代码

class Solution {
private:
    vector<int> preorder, inorder;

    TreeNode *dfs(int iPre, int jPre, int iIn, int jIn) {
        if (iPre == jPre) return nullptr;
        TreeNode *node = new TreeNode(preorder[iPre]);
        if (iPre + 1 == jPre) return node;
        int miIn = find(inorder.begin() + iIn, inorder.begin() + jIn, preorder[iPre]) - inorder.begin();
        int nLeft = miIn - iIn, nRight = jIn - miIn - 1;
        node->left = dfs(iPre + 1, iPre + 1 + nLeft, iIn, miIn);
        node->right = dfs(iPre + 1 + nLeft, jPre, miIn + 1, jIn);
        return node;
    }

public:
    TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
        this->preorder = move(preorder), this->inorder = move(inorder);
        return dfs(0, this->preorder.size(), 0, this->inorder.size());
    }
};

16. 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

Example 1

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true

Example 2

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true

提示:

  • m == board.length
  • n = board[i].length
  • 1 <= m, n <= 6
  • 1 <= word.length <= 15
  • boardword 仅由大小写英文字母组成

代码

const vector<pair<int, int>> DIR{{-1, 0}, {1,  0}, {0,  -1}, {0,  1}};

class Solution {
private:
    vector<vector<char>> board;
    string word;
    int m, n;
    bool visited[6][6]; // 回溯时将board[x][y]修改为'#'可不开辟visited

    bool dfs(int x, int y, int i) {
        if (i == word.size()) return true;
        if (x < 0 || y < 0 || x >= m || y >= n || visited[x][y] || board[x][y] != word[i]) return false;
        visited[x][y] = true;
        for (auto&[dx, dy]:DIR) {
            if (dfs(x + dx, y + dy, i + 1)) return true;
        }
        visited[x][y] = false;
        return false;
    }

public:
    bool exist(vector<vector<char>> &board, string &word) {
        memset(visited, 0, sizeof visited);
        m = board.size(), n = board[0].size();
        this->board = move(board), this->word = move(word);
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (dfs(i, j, 0)) return true;
            }
        }
        return false;
    }
};

17. 排序链表

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

Example 1

输入:head = [4,2,1,3]
输出:[1,2,3,4]

Example 2

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

提示:

  • 链表中节点的数目在范围 [0, 5 * 10^4]
  • -10^5 <= Node.val <= 10^5

代码

class Solution {
private:
    ListNode *merge(ListNode *head1, ListNode *head2) {
        ListNode *dummyHead = new ListNode;
        ListNode *node = dummyHead;
        while (head1 && head2) {
            if (head1->val > head2->val) swap(head1, head2);
            node = node->next = head1;
            head1 = head1->next;
        }
        node->next = head1 ? head1 : head2;
        return dummyHead->next;
    }

    ListNode *sortList(ListNode *head, ListNode *tail) {
        if (head == nullptr) return head;
        if (head->next == tail) {
            head->next = nullptr;
            return head;
        }
        auto slow = head, fast = head;
        while (fast != tail) {
            slow = slow->next, fast = fast->next;
            if (fast != tail) fast = fast->next;
        }
        return merge(sortList(head, slow), sortList(slow, tail));
    }

public:
    ListNode *sortList(ListNode *head) { return sortList(head, nullptr); }
};

17. 寻找重复数

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

Example 1

输入:nums = [1,3,4,2,2]
输出:2

Example 2

输入:nums = [3,1,3,4,2]
输出:3

提示:

  • 1 <= n <= 105
  • nums.length == n + 1
  • 1 <= nums[i] <= n
  • nums只有一个整数 出现 两次或多次 ,其余整数均只出现 一次

代码 [快慢指针]

class Solution {
public:
    int findDuplicate(vector<int> &nums) {
        int slow = 0, fast = 0;
        do {
            slow = nums[slow];
            fast = nums[nums[fast]];
        } while (slow != fast);
        slow = 0;
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值