LeetCode 刷题笔记---(六)

看理论看累了,过来刷会儿

ID:283

image-20240121210953805

思路历程:

看上去很简单,但其实还是要一点时间的,我觉得每次做题的时候真的不能犹豫,该用STL就用,别怕,大不了做出来了等面试官提额外要求,犹豫会浪费很多时间

解题思路:记录含0下标,vector进行erase(),注意这里的erase最好从最后开始,不然数组下标会变

answer:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n =nums.size();
        if(n==1)return;
        int i=0;
        vector<int>xb;
        while(i<n){
            if(nums[i]==0){
                xb.push_back(i);
            }
            i++;
        }
        int c=xb.size();
        while(c--){
            nums.erase(nums.begin()+xb[c]);
            nums.push_back(0);
        }
    }
};

题解思路:右指针从开头向后遍历,遇到非零的就放在开头(与开头的左指针替换)左指针右移

左指针的左边就是已经完成的序列


ID:20

居然又刷到了简单题

image-20240121213949572

虽然简单,用栈就能解决,但也花了一点时间

主要是逻辑运算没搞好

注意||两边要带括号

answer:

class Solution {
public:
    bool isValid(string s) {
        stack<char> stk;
        int i = 1;
        int n = s.size();
        if (n == 1)
            return false;

        stk.push(s[0]);
        while (i < n) {
            if (!stk.empty()) {
                char tmp = stk.top();
                if (tmp == '(' && s[i] == ')'){
                    stk.pop();i++;continue;
                }
                if (tmp == '[' && s[i] == ']'){
                    stk.pop();i++;continue;
                }
                if (tmp == '{' && s[i] == '}'){
                    stk.pop();i++;continue;
                }
                stk.push(s[i]);
            } else {
                stk.push(s[i]);
            }
            i++;
        }
        if (stk.empty()) {
            return true;
        } else{
            return false;
        }
    }
};

题解里有一个很牛的思路

class Solution {
    public boolean isValid(String s) {
        int length = s.length() / 2;
		for (int i = 0; i < length; i++) {
			s = s.replace("()", "").replace("{}", "").replace("[]", "");
		}
		return s.length() == 0;
    }
}

很厉害,一开始想有点难想到


ID:23

image-20240121224010660

虽然30minAC了,但是运行时间好长,近600ms

其他人只要20ms吗。。。

思路历程:

所有的list转成队列,然后取对头最小元素插入链表

answer:

/**
 * 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* mergeKLists(vector<ListNode*>& lists) {
        int n=lists.size();
        int nul=0;
        for(auto c:lists){
            if(c==nullptr){
                nul++;
            }
        }
        if(n==nul)return{};
        vector<queue<int>> all;
        ListNode* res=new ListNode();
        ListNode* head=res;
        int count=0;
        for(auto c:lists){
            queue<int> tmp;
            while(c){
                count++;
                tmp.push(c->val);
                c=c->next;
            }
            all.push_back(tmp);
        }
        while(count--){
            int minhead=10000;
            int idx;
            for(int i=0;i<n;i++){
                if(!all[i].empty()&&minhead>all[i].front()){
                    minhead=all[i].front();
                    idx=i;
                }
            }
            ListNode* node=new ListNode();
            if(count==0)node=nullptr;
            res->val=minhead;
            res->next=node;
            res=node;
            all[idx].pop();
        }
        return head;
    }
};

看看他们的优化答案:最小堆(优先队列)


ID:56

image-20240122122316533

唉,一路跟着没过用例改的...

思路历程:

一开始已经想到了,要先排序,但当时想的是,应该要根据平均值排序,但后来发现有的样例过不了,因为有些区间比较大,比如[8,9]和[1,10]这[1,10]肯定要放后面

所以后来改成了根据区间的右边界排,反正左边界可以处理

然后在删除区间的过程中,记得从后往前删

同时记得判断是否要改变左边界([1,4],[0,10])

answer:

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        int n=intervals.size();
        int i=0;
        sort(intervals.begin(),intervals.end(),[](vector<int>&a,vector<int>&b){
            return a[1]<b[1];
        });
        i=n-1;
        while(i>0){
            if(intervals[i][0]<=intervals[i-1][1]){
                if(intervals[i][0]>intervals[i-1][0]){
                    intervals[i][0]=intervals[i-1][0];
                }
                intervals.erase(intervals.begin()+i-1);
            }
            i--;
        }
        return intervals;
    }
};

ID:32

image-20240122125431953

思路历程:

一开始以为很简单,就是用栈,直到遇到了这个样例

"()(()"

...很尴尬,因为中间的(成了一个隔板,不知道该怎么处理

这个我可以在入栈时判断是否为空,空的话,把结果暂时存起来

但下面这个样例真过不了了...

"(()(((()"

看了题解....居然是dp...

...题解二是栈,我陷入了思维误区,只想着把括号放进去,其实可以把下标放进去,这样每次

可以记录最大状态

核心思路如下:

image-20240122134400072

class Solution {
public:
    int longestValidParentheses(string s) {
        int maxans = 0;
        stack<int> stk;
        stk.push(-1);
        for (int i = 0; i < s.length(); i++) {
            if (s[i] == '(') {
                stk.push(i);
            } else {
                stk.pop();
                if (stk.empty()) {
                    stk.push(i);
                } else {
                    maxans = max(maxans, i - stk.top());
                }
            }
        }
        return maxans;
    }
};

这里的栈底元素-1就是为了计算最深深度

如果出现了我上面说的隔板,就把-1弹出来,把隔板下标放进去


已经放假了,2天没刷题了,寒假好好学,好好刷题,好好准备

ID:141

image-20240127164441988

思路历程:

我就是很简单的暴力,用一个map存好节点,如果遇到之前的节点说明有环

answer:

class Solution {
public:
    bool hasCycle(ListNode *head) {
        map<ListNode*, int>node_map;
        ListNode* tmp=head;
        while(tmp){
            if(node_map.find(tmp)!=node_map.end()){
                return true;
            }else{
                node_map[tmp]=1;
            }
            tmp=tmp->next;
        }
        return false;
    }
};

看到一种题解,快慢指针,确实也很不错,快指针遇到null就false

如果有环的话,可以这样理解,一快一慢进入环形跑道,然后快的终将会追上慢的(套圈)

answer:

class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(!head||!head->next)return false;
        ListNode* slow=head;
        ListNode* fast=head->next;
        while(slow!=fast){
            if(!fast||!fast->next)return false;
            slow=slow->next;
            fast=fast->next->next;
        }
        return true;
    }
};

ID:11

image-20240127205232770

思路历程:

和之前的那个最大矩形有点像,单调栈和哨兵机制

哈哈哈哈

居然卡着时间线过了,笑死我了,看着示例绕过了一些恶心数据

这次其实也可以用栈的机制,找到最远的稍大值,(没有就比较当前值和加长矩形)

answer:

class Solution {
public:
    int maxArea(vector<int>& height) {
        //找一个最远的比自己大的作为边界
        int n=height.size();
        int i=0;
        int sub_res=0;
        while(i<n){
            if(!height[i]||sub_res/height[i]>(n-i)){
                i++;continue;
            }
            for(int j=i;j<n;j++){
                if(height[j]>height[i]){
                    sub_res=max(sub_res,(j-i)*height[i]);
                }else{
                    sub_res=max(sub_res,(j-i)*height[j]);
                }
            }
            i++;
        }
        return sub_res;
    }
};

看看题解

使用双指针进行操作,两边同时向中间靠拢


ID:98

image-20240127215806252

一道正常的DFS,但是只顾着判断当前子树的正确性,忘记判断整体二叉搜素树的正确性了,在函数封装时,得带上一个最小根值和最大根植才行,这样一层层遍历下去才能判断整体是否正确

另外,在判断值大小的时候,可以同时直接判断有无值,所以只需要一次判断

answer:

class Solution {
public:
    bool helper(TreeNode* root, long long lower, long long upper) {
        if (root == nullptr) {
            return true;
        }
        if (root -> val <= lower || root -> val >= upper) {
            return false;
        }
        return helper(root -> left, lower, root -> val) && helper(root -> right, root -> val, upper);
    }
    bool isValidBST(TreeNode* root) {
        return helper(root, LONG_MIN, LONG_MAX);
    }
};
文章作者: P4ul
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 打工人驿站
算法 c++
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝