力扣Hot100题单个人计划c++版(三)

力扣Hot100题单个人计划c++版(一)
力扣Hot100题单个人计划c++版(二)
力扣Hot100题单个人计划c++版(三)
力扣Hot100题单个人计划c++版(四)
力扣Hot100题单个人计划c++版(五)


刷题链接:力扣Hot 100
每日一题,每日一更,白板手写。


41.二叉树的层序遍历

10.11打卡
层序遍历很基础的算法了,按照每层返回一个vector的话,一开始想到用两个队列循环取每一层和下一层,然后在转成vector,当然题解更巧妙的做法是记住每层的大小即可。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(root==nullptr)return {};
        vector<vector<int>> ans;
        queue<TreeNode*> q;
        q.push(root);
        int cnt=-1;
        while(!q.empty()){
            int clen=q.size();
            ++cnt;
            ans.push_back(vector<int>());
            while(clen--){
                auto pos=q.front();q.pop();
                ans[cnt].push_back(pos->val);
                if(pos->left)q.push(pos->left);
                if(pos->right)q.push(pos->right);
            }
        }
        return ans;
    }
};

42.二叉树的最大深度

10.12打卡
递归可以有两种写法,一种是像下面这段代码一样,根节点初始化为0,从上往下搜索,每搜索一层就加一。

class Solution {
public:
    int treehigh(TreeNode* pos,int n){
        if(!pos)return n;
        return max(treehigh(pos->left,n+1),treehigh(pos->right,n+1));
    }
    int maxDepth(TreeNode* root) {
        return treehigh(root,0);
    }
};

也可以直到搜索至叶节点,让叶节点的下一层空节点为0,这样叶节点就是最低层为1,往上返回的过程中不断加1。

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(!root)return 0;
        return max(maxDepth(root->left),maxDepth(root->right))+1;
    }
};

还有可以用BFS,不断想下扩展层数,到边界就返回层数。广搜写太多了,此处就不写了。

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

10.15打卡。
递归好写,迭代难想,待补。

44.二叉树展开为链表

10.15打卡
递归的前序遍历很好写了。迭代待补。

class Solution {
public:
    void flatten(TreeNode* root) {
        vector<TreeNode*> list;
        pre(root,list);
        int n=list.size();
        for(int i=1;i<n;i++){
            TreeNode* t=list[i-1];
            t->left=nullptr;
            t->right=list[i];
        }
    }
    void pre(TreeNode* r,vector<TreeNode*>& l){
        if(!r)return;
        l.emplace_back(r);
        pre(r->left,l);
        pre(r->right,l);
    }
};

45.买卖股票的最佳时机

10.17打卡
《挑战程序设计》第二章入门题,经典dp,找到j之前的最小值即可。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int maxv=0;
        int minv=prices[0];
        int n=prices.size();
        for(int i=1;i<n;i++){
            if(minv>prices[i])minv=prices[i];
            else maxv=max(maxv,prices[i]-minv);
        }
        return maxv;
    }
};

46.二叉树中的最大路径和

10.17打卡
对于一个节点连接左右子树的路径,明显可以分成子问题,递归求左右子树的最大路径和即可。

class Solution {
public:
    int maxv;
    int dfs(TreeNode* pos){
        if(pos==nullptr)return 0;
        int t1=max(dfs(pos->left),0);
        int t2=max(dfs(pos->right),0);
        maxv=max(maxv,t1+t2+pos->val);
        return max(t1,t2)+pos->val;
    }
    int maxPathSum(TreeNode* root) {
        maxv=root->val;
        dfs(root);
        return maxv;
    }
};

47.最长连续序列

10.18打卡
原本以为 O ( n l o g n ) O(nlogn) O(nlogn)排序后再线性找是最快的。题解用哈希表直接 O ( n ) O(n) O(n)是最快的。

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        int maxv=0;
        int n=nums.size();
        unordered_set<int> hash;
        for(auto x:nums)hash.insert(x);
        for(const int& x:hash){
            if(hash.count(x-1))continue;
            int nxt=x+1;
            int clen=1;
            while(hash.count(nxt)){
                ++nxt;++clen;
            }
            maxv=max(maxv,clen);
            if(maxv>=(n>>1)+1)break;
        }
        return maxv;
    }
};

48.只出现一次的数字

10.19打卡
异或的独特性质。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ans=0;
        for(const int& x:nums)ans^=x;
        return ans;
    }
};

49.单词拆分

10.20打卡
待补,经典题。三种写法都试一遍。题解:剖析三种解法: DFS, BFS, 动态规划 |139.单词拆分

49.环形链表

10.21打卡
正常思路应该都是哈希表判断是否当前节点是否被访问过。

class Solution {
public:
    bool hasCycle(ListNode *head) {
        unordered_set<ListNode*> hash;
        ListNode* pos=head;
        while(pos!=nullptr&&!hash.count(pos)){
            hash.insert(pos);
            pos=pos->next;
        }
        if(pos)return true;
        return false;
    }
};

但这类题还有一个巧妙思路就是快慢指针。快指针走两步,慢指针走一步,如果有环那一定会相遇。这样就可以避免使用 O ( n ) O(n) O(n)的空间存储遍历过的节点。这个问题还有一个拓展:如何找出环的入口处呢?思路很简单,先用上面的方法找出快慢指针的相遇点,然后一个指向头结点,一个指向相遇点,两个节点同步移动,再次相遇处就是环的入口处。很好证明,画个草图就能明白。

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

51.环形链表II

10.23打卡
正是上一题的拓展。。。预言成真。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(!head||!head->next)return nullptr;
        ListNode* low=head;
        ListNode* fast=head;
        while(fast){
            if(!fast->next)return nullptr;
            low=low->next;
            fast=fast->next->next;
            if(low==fast){
                ListNode* pre=head;
                while(low!=pre){
                    low=low->next;
                    pre=pre->next;
                }
                return pre;
            }
        }
        return nullptr;
    }
};

52. LRU 缓存机制

10.23打卡
待补,考研复习到OS回过头补。

53.链表排序

10.24打卡
归并排序。但是想要达到常数级别的空间复杂度,需要自底向上归并,否则自顶向下递归会产生 O ( l o g n ) O(logn) O(logn)空间复杂度。简单来说,自底向下就是每次把链表分成小段,每次迭代长度依次增倍。合并相邻的链表即可。

class Solution {
public:
    ListNode* merge(ListNode* h1,ListNode* h2){
        ListNode* dummy=new ListNode(0);
        ListNode* t=dummy;
        ListNode* t1=h1,*t2=h2;
        while(t1&&t2){
            if(t1->val<t2->val){
                t->next=t1;
                t1=t1->next;
            }else{
                t->next=t2;
                t2=t2->next;
            }
            t=t->next;
        }
        if(t1)t->next=t1;
        else if(t2)t->next=t2;
        return dummy->next;
    }
    ListNode* sortList(ListNode* head) {
        if(!head)return nullptr;
        int len=0;
        ListNode* tmp=head;
        while(tmp){
            tmp=tmp->next;
            ++len;
        }
        ListNode* dummy=new ListNode(0,head);
        for(int p=1;p<len;p<<=1){
            ListNode* pre=dummy;
            ListNode* cur=dummy->next;
            while(cur){
                ListNode* h1=cur;
                for(int i=1;i<p&&(cur->next!=nullptr);++i)cur=cur->next;
                ListNode* h2=cur->next;
                cur->next=nullptr;
                cur=h2;
                for(int i=1;i<p&&cur!=nullptr&&cur->next!=nullptr;++i)cur=cur->next;
                ListNode* nxt=nullptr;
                if(cur){
                    nxt=cur->next;
                    cur->next=nullptr;
                }
                ListNode* ml=merge(h1,h2);
                pre->next=ml;
                while(pre->next!=nullptr)pre=pre->next;
                cur=nxt;
            }
        }
        return dummy->next;
    }
};

54.乘积最大子数组

10.26
动态规划永远的痛!

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n=nums.size();
        int maxv,minv,ans;
        maxv=minv=ans=nums[0];
        for(int i=1;i<n;++i){
            int t=maxv;
            maxv=max(nums[i]*maxv,max(minv*nums[i],nums[i]));
            minv=min(nums[i]*minv,min(t*nums[i],nums[i]));
            ans=max(maxv,ans);
        }
        return ans;
    }
};

55.最小栈

10.27打卡
很经典的解法,会者不难难者不会。确实很难想到用辅助栈存当前最小值。思路难想但是很简单,很巧妙的解法。

class MinStack {
public:
    stack<int> s;
    stack<int> mins;
    MinStack() {
        mins.push(INT_MAX);
    }
    
    void push(int val) {
        s.push(val);
        mins.push(min(mins.top(),val));
    }
    
    void pop() {
        s.pop();mins.pop();
    }
    
    int top() {
        return s.top();
    }
    
    int getMin() {
        return mins.top();
    }
};

56.相交链表

10.28打卡
原本思路是遍历a和b的长度,然后令一个节点从长链表移动k=len(a)-len(b)+1;然后另一个链表从头节点开始就可以相遇到。
不过也有只需要遍历更少的解法,即等一个节点到尾部后就把它放到另一个链表的头结点即可。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA==nullptr||headB==nullptr)return nullptr;
        ListNode *ha=headA,*hb=headB;
        while(ha!=hb){
            if(ha)ha=ha->next;
            else ha=headB;
            if(hb)hb=hb->next;
            else hb=headA;
        }
        return ha;
    }
};

57.多数元素

10.30打卡
找出超过一半的数字,经典问题,投票算法可解,投票算法其实也可以这么理解:当减掉两个相异元素时,超过一半的数不会变。因为如果是目标数和其他数,去掉这两个结果仍不变,如果都不是目标数,那结果也不变。这样消去相异元素直到剩下最后相同的数,那个数就是目标数。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int ans=-1;
        int cnt=0;
        for(int &x:nums){
            if(x==ans)++cnt;
            else if(--cnt<0){
                ans=x;;
                cnt=1;
            }
        }
        return ans;
    }
};

58.打家劫舍

10.30打卡
动态规划,应该很好想出来。对于当前的数,要么取这个加前n-2个最大的,要么不取加前n-1最大的。

class Solution {
public:
    int rob(vector<int>& nums) {
        int n=nums.size();
        if(n==1)return nums[0];
        if(n==2)return max(nums[0],nums[1]);
        vector<int> dp(n,0);
        dp[0]=nums[0];
        dp[1]=max(nums[0],nums[1]);
        for(int i=2;i<n;++i){
            dp[i]=max(dp[i-1],nums[i]+dp[i-2]);
        }
        return dp[n-1];
    }
};

59.岛屿数量

10.31打卡
求连通集,深搜广搜查并集均可。以下为深搜。

class Solution {
public:
    vector<int> dx={1,0,0,-1};
    vector<int> dy={0,1,-1,0};
    void dfs(int cx,int cy,int n,int m,vector<vector<char>>& g){
        if(g[cx][cy]!='1')return;
        g[cx][cy]='0';
        for(int i=0;i<4;++i){
            int nx=cx+dx[i],ny=cy+dy[i];
            if(nx<0||ny<0||nx>=n||ny>=m)continue;
            dfs(nx,ny,n,m,g);
        }
    }
    int numIslands(vector<vector<char>>& grid) {
        int n=grid.size();
        if(!n)return 0;
        int m=grid[0].size();
        int cnt=0;
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                if(grid[i][j]=='1'){
                    ++cnt;
                    dfs(i,j,n,m,grid);
                }
            }
        }
        return cnt;
    }
};

60.反转链表

11.1打卡
这应该是必刷题了吧。面试常见简单题。

  1. 迭代版
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *pre=nullptr;
        ListNode *cur=head;
        while(cur){
            ListNode* nxt=cur->next;
            cur->next=pre;
            pre=cur;
            cur=nxt;
        }
        return pre;
    }
};
  1. 递归版
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(!head||!head->next)return head;
        ListNode* newhead=reverseList(head->next);
        head->next->next=head;
        head->next=nullptr;
        return newhead;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值