LeetCode 刷题笔记(七)

写完了CPP版tinyhttpd,过来刷会儿题

这次的主题是回溯和链表

ID:46

image-20240305215751431

思路历程:

今天看了代码随想录的视频,介绍了回溯算法的基本思路

就是递归中,判断边界

然后遍历元素,处理数据,调用递归,撤销处理(回溯)

值得注意的是,回溯算法一般会用到set,如果不用set用vector的话,记得加一个状态数组

如下:

class Solution {
public:
    vector<vector<int>> res;
    vector<int> sub_res;

    void bkt(vector<int>& nums, vector<bool>& used) {
        if (sub_res.size() == nums.size()) {
            res.push_back(sub_res);
            return;
        }

        for (int i = 0; i < nums.size(); ++i) {
            if (!used[i]) {
                used[i] = true;
                sub_res.push_back(nums[i]);

                bkt(nums, used); // 递归调用

                // 回溯
                used[i] = false;
                sub_res.pop_back();
            }
        }
    }

    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool> used(nums.size(), false); // 初始化为未使用
        bkt(nums, used);
        return res;
    }
};

answer:(unordered_set)

class Solution {
public:
    vector<vector<int>>res;    
    vector<int>sub_res;
    void bkt(unordered_set<int> all_nums){
        if(all_nums.empty()){
            res.push_back(sub_res);
            return ;
        }
        for(auto iter=all_nums.begin();iter!=all_nums.end();++iter){
            int c=*iter;
            sub_res.push_back(c);
            unordered_set<int>temp=all_nums;
            temp.erase(c);
            bkt(temp);
            sub_res.pop_back();
        }
    }
    
    vector<vector<int>> permute(vector<int>& nums) {
        unordered_set<int>all_nums;
        for(auto c:nums)all_nums.insert(c);
        bkt(all_nums);
        return res;
    }
};

ID:78

image-20240305223813470

思路历程:

感觉所谓的模板不能以偏概全

不一定会有遍历,返回和处理数据是必要的

子集可以是这样,我从数组头出发,选择要当前的或者不要,然后往后走(重新调用)

answer:

class Solution {
public:
    vector<vector<int>>res;
    vector<int>sub_res;
    void bkt(int now,vector<int>&nums,int n){
        if(now==n){
            res.push_back(sub_res);
            return;
        }
        sub_res.push_back(nums[now]);
        bkt(now+1,nums,n);
        sub_res.pop_back();
        bkt(now+1,nums,n);
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        int n=nums.size();
        bkt(0,nums,n);
        return res;
    }
};

ID:21

image-20240306135837925

思路历程:

非常的简单,不要想复杂,拿出一格头节点和队列一样,一个个收进来就行

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* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode* res=nullptr;
        ListNode* fin_res=nullptr;
        if(list1&&list2){
            fin_res=list1->val<=list2->val?list1:list2;
        }else{
            if(list1)fin_res=list1;
            if(list2)fin_res=list2;
            return fin_res;
        }
        ListNode*tmp;
        while(list1&&list2){
            if(list1->val<=list2->val){
                if(!res){
                    res=list1;
                }else{
                    res->next=list1;
                    res=res->next;
                }
                list1=list1->next;
            }else{
                if(!res){
                    res=list2;
                }else{
                    res->next=list2;
                    res=res->next;
                }
                list2=list2->next;
            }
        }
        if(list1)res->next=list1;
        if(list2)res->next=list2;
        return fin_res;
    }
};

ID:2

image-20240306150334142

思路历程:

一开始我还是想的比较简单,一环环往后就行,遇到进位就记录,但到后面真有点恶心到了

上一轮的进位会影响到这一轮,应该先存节点,再考虑进位,不然会相互干扰

同时如果遇到有长短链表,建议先增长至一直,不要和我一样偷懒,加完一条后,再处理剩下那条

新思路中有一点要注意的是,补0节点时,最好从尾节点开始,而不是尾节点->next

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* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode*res=nullptr;
        ListNode*fin_res=nullptr;
        int flag=0;
        ListNode*head1=l1;ListNode*head2=l2;
        int length1=0,length2=0;
        while(head1->next){
            length1++;head1=head1->next;
        }
        while(head2->next){
            length2++;head2=head2->next;
        }
        if(l1->val==0&&length1==1)return l2;
        if(l2->val==0&&length2==1)return l1;
        while(length1<length2){
            head1->next=new ListNode(0);
            head1=head1->next;
            length1++;
        }
        while(length2<length1){
            head2->next=new ListNode(0);
            head2=head2->next;
            length2++;
        }
        if((l1->val+l2->val)/10)flag=1;
        res=new ListNode((l1->val+l2->val)%10);
        l1=l1->next;l2=l2->next;fin_res=res;
        while(l1&&l2){
            int sum=l1->val+l2->val+flag;//上个flag
            res->next=new ListNode(sum%10);
            if(flag)flag=0;
            l1=l1->next;l2=l2->next;res=res->next;
            if(sum>=10)flag=1;
        }
        if(flag)res->next=new ListNode(1);
        return fin_res;
    }
};

ID:19

image-20240307110516142

思路历程:

思考起来会比较简单,遍历链表记录长度,然后获取要删除节点的下标,然后再次遍历处理即可

注意的点是如果要删除的是第一个节点,直接返回head->next即可

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* removeNthFromEnd(ListNode* head, int n) {
        int length=0;
        ListNode*tmp=head;
        while(tmp){
            length++;tmp=tmp->next;
        }
        tmp=head;ListNode* res;
        int idx=length-n;
        if(!idx){
            return head->next;
        }else{
            int i=0;
            while(i<idx-1){
                tmp=tmp->next;
                i++;
            }
            tmp->next=tmp->next->next;
        }
        return head;
    }
};

ID:24

image-20240307133945451

思路历程:

有一说一,做完还是有点蒙,

总体思路是,每次遇到下标为奇数,就去交换位置,

换的时候,pre->next=back;now->next=back->next;back->next=now;

不换的时候 pre=now;now=now->next;back=now->next;

注意考虑第一个pre为nullptr的时候

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* swapPairs(ListNode* head) {
        ListNode*pre=nullptr;
        ListNode*now;ListNode*back;ListNode*tmp=head;
        int length=0;
        while(tmp){
            length++;tmp=tmp->next;
        }
        if(length<=1)return head;
        std::cout<<length<<std::endl;
        tmp=head;now=head;back=head->next;
        int i=1;
        ListNode* res;
        while(i<length){
            i++;
            if(i%2==0){
                if(pre){
                    pre->next=back;
                    now->next=back->next;
                    back->next=now;
                }else{
                    now->next=back->next;
                    back->next=now;
                    pre=back;
                    back=now->next;
                }
                if(i==2)res=pre;
                continue;
            }
            pre=now;
            now=now->next;
            back=now->next;
        }
        return res;
    }
};

ID:138

image-20240307142524497

思路历程:

next指针拷贝非常简单,主要问题在于random怎么实现深拷贝

我一开始想的是,存下标,自定义一个计数器,然后用map存两边的下标,就能实现再次遍历的时候深拷贝random

但问题在于,我拷贝下标是不够的,因为我random指向的是指针而不是下标,所以优化一下

我们选择存两边对应的地址(指针)那么我只要再次遍历时,取出原节点的random,然后放入map,就可以拿到本节点的random地址

answer:

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(!head)return NULL;
        Node*tmp=head;tmp=tmp->next;
        Node*res=new Node(head->val);
        Node*node=res;
        map<Node*,Node*> ptr_hash;//存下标和映射下标
        ptr_hash.insert({head,res});
        while(tmp){
            node->next=new Node(tmp->val);
            node=node->next;
            ptr_hash.insert({tmp,node});
            tmp=tmp->next;
        }
        tmp=head;node=res;
        while(tmp){
            node->random=ptr_hash[tmp->random];
            node=node->next;
            tmp=tmp->next;
        }
        return res;
    }
};

ID:148

image-20240307150941924

思路历程:

如果不考虑空间和时间复杂度会很简单,但如果考虑的话,就比较麻烦了

比如说用到归并排序的思想,就能实现O(nlogn)时间复杂度和O(logn)空间复杂度

image-20240307151143422

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* sortList(ListNode* head) {
        if(!head)return nullptr;
        ListNode*node =head;
        vector<int> nums;
        while(node){
            nums.push_back(node->val);
            node=node->next;
        }
        sort(nums.begin(),nums.end());
        ListNode*res=nullptr;
        ListNode*fin;
        for(auto c:nums){
            if(!res){
                res=new ListNode(c);
                fin=res;
            }else{
                res->next=new ListNode(c);
                res=res->next;
            }
        }
        return fin;
    }
};

继续加油,许愿快速OC

文章作者: P4ul
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 打工人驿站
算法 c++
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝