Leetcode 81-90

LeetCode 81. 搜索旋转排序数组 II

分析

因为有重复数字的存在, 旋转后的数组第一个数 可能和最后一个数相等, 这样的话, 就不容易判断target到底属于 前半段区间, 还是后半段区间.
因此需要加个while循环, 排除重复元素, 并不影响结果的判定.
因为后一个区间的值全是小于nums[0]的,
所以可以通过二分, 找到前半段区间的右端点的值, 即>= nums[0]最靠右的值
然后让判断target是否在所找的区间内部即可.

code

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        if (nums.empty()) return false;
        int R = nums.size() - 1;
        while (R > 0 && nums[0] == nums[R]) R --;
        if (R < 0) return nums[0] == nums[R]; // R < 0 说明整个数组全是同1个数

        int l = 0, r = R;
        while (l < r){
            int mid = l + r + 1 >> 1;
            if (nums[mid] >= nums[0]) l = mid;
            else r = mid - 1;
        }
        
        if (target >= nums[0]) r = l, l = 0;
        else l ++, r = R; // 注意l ++, 以下数据会导致越界
        // 数据 1 3 0 在上一重二分输出 l = 1, r = 1
        // 然后进入else 分支l ++, l = 2, r = 1, 导致l越界.
        // 因此 最后return num[r] 而不是 nums[l]
        
        while (l < r){
            int mid = l + r >> 1;
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;
        }
        return target == nums[r];
    }
};

LeetCode 82. 删除排序链表中的重复元素 II

分析

注意 题目要求将所有相同的删掉, 一个都不保留, 相同的全部删掉
p代表重复元素的前一个元素
在这里插入图片描述

code

/**
 * 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) {
        auto dummy = new ListNode(-1);
        dummy->next = head;
        auto p = dummy;
        while (p->next){
            auto q = p->next->next;
            while (q && q->val == p->next->val) q = q->next; //找出相同的一段[p, q)
            if (p->next->next == q) p = p->next; //如果p = q, 那么表示相同的这一段只有一个数,那么p后移动一位
            else p->next = q;// 否则, p的下一个位置指向q
        }
        return dummy->next;
    }
};

LeetCode 83. 删除排序链表中的重复元素

分析

如果当前的值与下一个值相等, 则跳过p->next, 即p->next = p->next->next
否则p往后走一步.
在这里插入图片描述

code

/**
 * 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;
        auto p = head;
        while (p->next){
            if (p->val == p->next->val) p->next = p->next->next;
            else p = p->next;
        }
        return head;
    }
};

LeetCode 84. 柱状图中最大的矩形

分析

单调栈, 分别对左边和右边做单调栈, 然后计算最大值即可
left 表示比当前低的竖条, 最左边界,
right 表示比当前低的竖条, 最右边界

code

class Solution {
public:
    int largestRectangleArea(vector<int>& h) {
        stack<int> stk;
        int n = h.size();
        vector<int> left(n), right(n);

        for (int i = 0; i < n; i ++ ){
            while (stk.size() && h[stk.top()] >= h[i]) stk.pop();
            if (stk.empty()) left[i] = -1;
            else left[i] = stk.top();
            stk.push(i);
        }
        stk = stack<int>();
        for (int i = n - 1; i >= 0; i -- ){
            while (stk.size() && h[stk.top()] >= h[i]) stk.pop();
            if (stk.empty()) right[i] = n;
            else right[i] = stk.top();
            stk.push(i);
        }

        int res = 0;
        for (int i = 0; i < n; i ++ )
            res = max(res, (right[i] - left[i] - 1) * h[i]);
        return res;
    }
};

LeetCode 85. 最大矩形

分析

只需计算出每层matrix 往上的最大高度, 然后对每一层应用上一题的最大矩形, 即可求出整个矩形的最大矩形.

code

class Solution {
public:
    int largestRectangleArea(vector<int>& h) {
        int n = h.size();
        vector<int> left(n), right(n);
        stack<int> stk;

        for (int i = 0; i < n; i ++ ) {
            while (stk.size() && h[stk.top()] >= h[i]) stk.pop();
            if (stk.empty()) left[i] = -1;
            else left[i] = stk.top();
            stk.push(i);
        }

        stk = stack<int>();
        for (int i = n - 1; i >= 0; i -- ) {
            while (stk.size() && h[stk.top()] >= h[i]) stk.pop();
            if (stk.empty()) right[i] = n;
            else right[i] = stk.top();
            stk.push(i);
        }

        int res = 0;
        for (int i = 0; i < n; i ++ ) {
            res = max(res, h[i] * (right[i] - left[i] - 1));
        }

        return res;
    }
    int maximalRectangle(vector<vector<char>>& matrix) {
        if (matrix.empty() || matrix[0].empty()) return 0;
        int n = matrix.size(), m = matrix[0].size();

        vector<vector<int>> h(n, vector<int>(m));

        for (int i = 0; i < n; i ++ )   
            for (int j = 0; j < m; j ++ )
                if (matrix[i][j] == '1')
                    if (i) h[i][j] = h[i - 1][j] + 1;
                    else h[i][j] = 1;

        int res = 0;
        for (int i = 0; i < n; i ++ ) res = max(res, largestRectangleArea(h[i]));

        return res;
    }
};

LeetCode 86. 分隔链表

分析

类似于快排, 排序链表, 但不改变链表的相对顺序, 所以新建左右两个链表, 将<x的节点接到左边, >= x的接到右边, 然后左边尾部指向右边头部
在这里插入图片描述

code

/**
 * 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* partition(ListNode* head, int x) {
        auto lh = new ListNode(-1), rh = new ListNode(-1);
        auto lt = lh, rt = rh;
        
        for (auto p = head; p; p = p->next){
            if (p->val < x) lt = lt->next = p;
            else rt = rt->next = p;
        }
        lt->next = rh-> next;
        rt->next = nullptr;
        return lh->next;
    }   
};

LeetCode 87. 扰乱字符串

分析

按照题目要求, 两个字符串可以变成同一个, 只有当对两个字符串排序完, 每个字符对应, 就说明可以变成另一个.
所以递归枚举分割点
第一个字符串前i个 转换成 第二个字符串前i个
或者
第一个字符串前i个 转换成 第二个字符串后i个 并且
第一个字符串后n - i个s1.substr(i) 转换成 第二个字符串的前n - i个

code(leetcode数据改了,TLE了)

class Solution {
public:
    bool isScramble(string s1, string s2) {
        if (s1 == s2) return true;
        int n = s1.size();
        string ss1 = s1, ss2 = s2;
        sort(ss1.begin(), ss1.end()), sort(ss2.begin(), ss2.end());
        if (ss1 != ss2) return false;

        for (int i = 1; i < n; i ++ ){
        	// 注意题目判断的s1 与 s2能否扰乱相同
        	// 因此下面必须对s1 和 s2递归, 不能对ss1 和 ss2 递归
            if (isScramble(s1.substr(0, i), s2.substr(0, i)) && isScramble(s1.substr(i), s2.substr(i))) return true;
            if (isScramble(s1.substr(0, i), s2.substr(n - i)) && isScramble(s1.substr(i), s2.substr(0, n - i))) return true;
        }
        return false;
    }
};

code(dp)

参考

class Solution {
public:
    bool isScramble(string s1, string s2) {
        int n = s1.size();
        vector<vector<vector<bool>>> f(n, vector<vector<bool>>(n, vector<bool>(n + 1)));

        for (int k = 1; k <= n; k ++ )
            for (int i = 0; i + k - 1 < n; i ++ )
                for (int j = 0; j + k - 1 < n; j ++ )
                    if (k == 1) {
                        if (s1[i] == s2[j]) f[i][j][k] = true;
                    }else {
                        for (int u = 1; u < k; u ++ )
                            if (f[i][j][u] && f[i + u][j + u][k - u] || f[i][j + k - u][u] && f[i + u][j][k - u]) {
                                f[i][j][k] = true;
                                break;
                            }

                    }
        return f[0][0][n];
    }
};

LeetCode 88. 合并两个有序数组

分析

归并排序的内容, 模版题
nums1数组范围比较大, 因此倒着放置

code

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int k = n + m - 1;
        int i = m - 1, j = n - 1;
        while (i >= 0 && j >= 0){
            if (nums1[i] >= nums2[j]) nums1[k --] = nums1[i --];
            else nums1[k --] = nums2[j --];
        }
        while (j >= 0) nums1[k -- ] = nums2[j --];
        // 因为最后一个循环是往nums1中放nums1剩余的数据, 本来就在位置上, 可以省略了
    }
};

LeetCode 89. 格雷编码

分析

先末尾添加0, 相当于左移1位, 由于镜像复制, 需要立即push_back当前的数,
因此push_back(res[i] + 1)

code

class Solution {
public:
    vector<int> grayCode(int n) {
        vector<int> res;
        res.push_back(0);
        while (n -- ){
            for (int i = res.size() - 1; i >= 0; i -- ){
                res[i] *= 2;
                res.push_back(res[i] + 1);
            }
        }
        return res;
    }
};

LeetCode 90. 子集 II

分析

for (int i = 0; i <= k - u; i ++){ ... }
递归树如下图
在这里插入图片描述

code

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        dfs(0, nums);
        return res;
    }
    void dfs(int u, vector<int>& nums){
        if (u == nums.size()){
            res.push_back(path);
            return;
        }

        int k = u;
        while (k < nums.size() && nums[k] == nums[u]) k ++;
        
        for (int i = 0; i <= k - u; i ++ ){
            dfs(k, nums);
            path.push_back(nums[u]);
        }

        for (int i = 0; i <= k - u; i ++ )
            path.pop_back();
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值