zoukankan      html  css  js  c++  java
  • LeetCode—剑指 Offer学习计划 友人

    个人博客中同步更新

    第 1 天 栈与队列(简单)

    剑指 Offer 09. 用两个栈实现队列

    点击查看代码
    class CQueue {
    public:
        CQueue() {
    
        }
        stack<int>s1,s2;
        void appendTail(int value) {
            s1.push(value);
        }
        
        int deleteHead() {
            if(s2.empty())
            {
                while(!s1.empty())
                {
                    s2.push(s1.top());
                    s1.pop();
                }
            }
            if(s2.empty())
                return -1;
            int tmp=s2.top();
            s2.pop();
            return tmp;
        }
    };
    
    /**
     * Your CQueue object will be instantiated and called as such:
     * CQueue* obj = new CQueue();
     * obj->appendTail(value);
     * int param_2 = obj->deleteHead();
     */
    

    剑指 Offer 30. 包含min函数的栈

    点击查看代码

    构造一个辅助栈,使辅助栈顶元素始终为当前栈内元素的最小值

    class MinStack {
    public:
        /** initialize your data structure here. */
        MinStack() {
            
        }
        stack<int>st;
        stack<int>m;
        void push(int x) {
            st.push(x);
            if(m.empty()||m.top()>=x)
                m.push(x);
        }
        
        void pop() {
            if(st.top()==m.top())
                m.pop();
            st.pop();
        }
        
        int top() {
            return st.top();
        }
        
        int min() {
            return m.top();
        }
    };
    
    /**
     * Your MinStack object will be instantiated and called as such:
     * MinStack* obj = new MinStack();
     * obj->push(x);
     * obj->pop();
     * int param_3 = obj->top();
     * int param_4 = obj->min();
     */
    

    第 2 天 链表(简单)

    剑指 Offer 06. 从尾到头打印链表

    存入数组中然后反转一下

    点击查看代码
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> reversePrint(ListNode* head) {
            vector<int>v;
            while(head)
            {
                v.push_back(head->val);
                head=head->next;
            }
            reverse(v.begin(),v.end());
            return v;
        }
    };
    

    剑指 Offer 24. 反转链表

    让当前节点的下一个节点指向上一个节点,使用一个临时的指针来实现

    点击查看代码
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* reverseList(ListNode* head) {
            ListNode *cnt=head,*ans=NULL;
            while(cnt)
            {
                ListNode *tmp=cnt->next;
                cnt->next=ans;
                ans=cnt;
                cnt=tmp;
            }
            return ans;
        }
    };
    

    剑指 Offer 35. 复杂链表的复制

    待补

    第三天 字符串(简单)

    剑指 Offer 05. 替换空格

    直接遍历

    点击查看代码
    class Solution {
    public:
        string replaceSpace(string s) {
            string ans;
            for(auto i:s)
            {
                if(i==' ')
                    ans+="%20";
                else
                    ans+=i;
            }
            return ans;
        }
    };
    

    剑指 Offer 58 - II. 左旋转字符串

    点击查看代码
    class Solution {
    public:
        string reverseLeftWords(string s, int n) {
            string ans="";
            ans+=s.substr(n,s.size());
            ans+=s.substr(0,n);
            return ans;
        }
    };
    

    第 4 天 查找算法(简单)

    剑指 Offer 03. 数组中重复的数字

    构建元素的索引和值为一对一的关系,如果当前索引已经有值并且和当前值相同,则出现多次

    点击查看代码
    class Solution {
    public:
        int findRepeatNumber(vector<int>& nums) {
            int l=nums.size();
            int i=0;
            while(i<l)
            {
                if(nums[i]==i)
                {
                    i++;
                    continue;
                }
                if(nums[nums[i]]==nums[i])
                    return nums[i];
                swap(nums[i],nums[nums[i]]);
            }
            return -1;
        }
    };
    

    剑指 Offer 53 - I. 在排序数组中查找数字 I

    lower_boundupper_bound的使用

    点击查看代码
    class Solution {
    public:
        int search(vector<int>& nums, int target) {
            int l_place=lower_bound(nums.begin(),nums.end(),target)-nums.begin();
            int r_place=upper_bound(nums.begin(),nums.end(),target)-nums.begin();
            return r_place-l_place;
        }
    };
    

    剑指 Offer 53 - II. 0~n-1中缺失的数字

    遍历

    点击查看代码
    class Solution {
    public:
        int missingNumber(vector<int>& nums) {
            int l=nums.size();
            for(int i=0;i<l;i++)
            {
                if(nums[i]!=i)
                    return i;
            }
            return l;
        }
    };
    

    二分

    点击查看代码
    class Solution {
    public:
        int missingNumber(vector<int>& nums) {
            int l=0,r=nums.size()-1;
            while(l<=r)
            {
                int mid=(l+r)/2;
                if(nums[mid]>mid)
                    r=mid-1;
                else
                    l=mid+1;
            }
            return l;
        }
    };
    

    第 5 天 查找算法(中等)

    剑指 Offer 04. 二维数组中的查找

    二分

    对每一行进行二分,时间复读\(O(n \log(m))\)

    点击查看代码
    class Solution {
    public:
        bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
            for(auto i:matrix)
            {
                int place=lower_bound(i.begin(),i.end(),target)-i.begin();
                if(place!=i.size()&&i[place]==target)
                    return true;
            }
            return false;
        }
    };
    

    线性查找

    从右上角开始,如果当前元素比target大,往左走;如果比target小,向下走。时间复杂度为\(O(n+m)\)
    [font color="red"]注意数组为空的情况[/font]

    点击查看代码
    class Solution {
    public:
        bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
            int n=matrix.size();
            if(!n) return false;
            int m=matrix[0].size();
            int i=0,j=m-1;
            while(i<n&&j>=0)
            {
                if(matrix[i][j]<target)
                    i++;
                else if(matrix[i][j]>target)
                    j--;
                else
                    return true;
            }
            return false;
        }
    };
    

    剑指 Offer 11. 旋转数组的最小数字

    遍历

    点击查看代码
    class Solution {
    public:
        int minArray(vector<int>& numbers) {
            int ans=numbers[0];
            for(auto i:numbers)
                ans=min(ans,i);
            return ans;
        }
    };
    

    二分

    注意相等的情况,需要遍历

    点击查看代码
    class Solution {
    public:
        int minArray(vector<int>& numbers) {
            int l=0,r=numbers.size()-1;
            int ans=10000000;
            while(l<r)
            {
                int mid=(l+r)/2;
                if(numbers[mid]>numbers[r])
                    l=mid+1;
                else if(numbers[mid]<numbers[r])
                    r=mid;
                else
                {
                    for(int i=l;i<=r;i++)
                        ans=min(ans,numbers[i]);
                    return ans;
                }
            }
            return numbers[l];
        }
    };
    

    剑指 Offer 50. 第一个只出现一次的字符

    直接用map存就行,可以把字符去一下重优化时间

    点击查看代码
    class Solution {
    public:
        char firstUniqChar(string s) {
            unordered_map<char,int>mp;
            char ans=' ';
            vector<char>v;
            for(auto i:s)
            {
                if(!mp[i])
                    v.push_back(i);
                mp[i]++;
            }
            for(auto i:v)
            {
                if(mp[i]==1)
                    return i;
            }
            return ans;
        }
    };
    

    第 6 天 搜索与回溯算法(简单)

    剑指 Offer 32 - I. 从上到下打印二叉树

    点击查看代码
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> levelOrder(TreeNode* root) {
            queue<TreeNode*>que;
            que.push(root);
            vector<int>ans;
            if(!root)
                return ans;
            while(!que.empty())
            {
                TreeNode *tmp=que.front();
                que.pop();
                if(tmp->left)
                    que.push(tmp->left);
                if(tmp->right)
                    que.push(tmp->right);
                ans.push_back(tmp->val);
            }
            return ans;
        }
    };
    

    剑指 Offer 32 - II. 从上到下打印二叉树 II

    在当前节点的下一层放入队列之前,把当前节点存下来

    点击查看代码
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<vector<int>> levelOrder(TreeNode* root) {
            if(!root)
                return {};
            queue<TreeNode*>que;
            que.push(root);
            vector<vector<int> >ans;
            while(!que.empty())
            {
                vector<int>tmp;
                int sz=que.size();
                for(int i=0;i<sz;i++)
                {
                    TreeNode *now=que.front();
                    tmp.push_back(now->val);
                    que.pop();
                    if(now->left)
                        que.push(now->left);
                    if(now->right)
                        que.push(now->right);
                }
                ans.push_back(tmp);
            }
            return ans;
        }
    };
    

    剑指 Offer 32 - III. 从上到下打印二叉树 III

    和上一题一样,只不过在存入到最终结果之前需要判断一下当前在第几层,翻转一下

    点击查看代码
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<vector<int>> levelOrder(TreeNode* root) {
            if(!root)
                return {};
            queue<TreeNode*>que;
            que.push(root);
            vector<vector<int> >ans;
            while(!que.empty())
            {
                vector<int>tmp;
                int sz=que.size();
                for(int i=0;i<sz;i++)
                {
                    TreeNode *now=que.front();
                    tmp.push_back(now->val);
                    que.pop();
                    if(now->left)
                        que.push(now->left);
                    if(now->right)
                        que.push(now->right);
                }
                if(ans.size()%2)
                    reverse(tmp.begin(),tmp.end());
                ans.push_back(tmp);
            }
            return ans;
        }
    };
    

    第 7 天 搜索与回溯算法(简单)

    剑指 Offer 26. 树的子结构

    先从A开始往下遍历,如果出现了与B的根节点相等的节点,开始A和B同时向下递归

    点击查看代码
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        bool isSubStructure(TreeNode* A, TreeNode* B) {
            if(!A||!B)
                return false;
            if(dfs(A,B))
                return true;
            return isSubStructure(A->left,B)||isSubStructure(A->right,B);
        }
        bool dfs(TreeNode *A,TreeNode *B)
        {
            if(!B)
                return true;
            if(!A)
                return false;
            if(A->val!=B->val)
                return false;
            return dfs(A->left,B->left)&&dfs(A->right,B->right);
        }
    };
    

    剑指 Offer 27. 二叉树的镜像

    BFS

    用栈辅助遍历来实现二叉树的镜像

    点击查看代码
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* mirrorTree(TreeNode* root) {
            if(!root)
                return root;
            stack<TreeNode*>st;
            st.push(root);
            while(!st.empty())
            {
                TreeNode *node=st.top();
                st.pop();
                if(node->left)
                    st.push(node->left);
                if(node->right)
                    st.push(node->right);
                TreeNode *tmp=node->left;
                node->left=node->right;
                node->right=tmp;
            }
            return root;
        }
    };
    

    DFS

    点击查看代码
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* mirrorTree(TreeNode* root) {
            if(!root)
                return root;
            TreeNode *node=root->left;
            root->left=mirrorTree(root->right);
            root->right=mirrorTree(node);
            return root;
        }
    };
    

    剑指 Offer 28. 对称的二叉树

    对左子树和右子树同时向下遍历

    点击查看代码
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        bool isSymmetric(TreeNode* root) {
            if(!root)
                return true;
            return dfs(root->left,root->right);
        }
        bool dfs(TreeNode *A,TreeNode *B)
        {
            if(!A&&!B)
                return true;
            if((!A||!B)||A->val!=B->val)
                return false;
            return dfs(A->left,B->right)&&dfs(A->right,B->left);
        }
    };
    

    第 8 天 动态规划(简单)

    剑指 Offer 10- I. 斐波那契数列

    别用递归写就行了

    点击查看代码
    class Solution {
    public:
        int a[3];
        const int mod=1e9+7;
        int fib(int n) {
            if(n<2)
                return n;
            a[0]=0;a[1]=1;
            for(int i=2;i<=n;i++)
            {
                a[2]=(a[1]%mod+a[0]%mod)%mod;
                a[0]=a[1];a[1]=a[2];
            }
            return a[2];
        }
    };
    

    剑指 Offer 10- II. 青蛙跳台阶问题

    \(dp[i]=dp[i-1]+dp[i-2]\)

    点击查看代码
    class Solution {
    public:
        int dp[101];
        const int mod=1e9+7;
        int numWays(int n) {
            dp[0]=1;
            dp[1]=1;
            dp[2]=2;
            for(int i=2;i<=n;i++)
                dp[i]=(dp[i-1]+dp[i-2])%mod;
            return dp[n];
        }
    };
    

    剑指 Offer 63. 股票的最大利润

    不断更新当前元素与当前最小值的差值就行了

    点击查看代码
    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            int sz=prices.size();
            if(!sz)
                return 0;
            int m=prices[0];
            int ans=0;
            for(int i=1;i<sz;i++)
            {
                m=min(prices[i],m);
                ans=max(ans,prices[i]-m);
            }
            return ans;
        }
    };
    

    第 9 天 动态规划(中等)

    剑指 Offer 42. 连续子数组的最大和

    点击查看代码
    class Solution {
    public:
        int maxSubArray(vector<int>& nums) {
            int ans=nums[0];
            int tmp=0;
            for(auto i:nums)
            {
                tmp=max(tmp+i,i);
                ans=max(ans,tmp);
            }
            return ans;
        }
    };
    

    剑指 Offer 47. 礼物的最大价值

    \(dp[i][j]=\max\{dp[i-1][j]+a[i][j],dp[i][j-1]+a[i][j],dp[i][j] \}\)

    点击查看代码
    class Solution {
    public:
        int dp[202][202];
        int maxValue(vector<vector<int>>& grid) {
            int n=grid.size(),m=grid[0].size();
            dp[0][0]=grid[0][0];
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<m;j++)
                {
                    if(!i&&!j)
                        continue;
                    if(!i)
                        dp[i][j]=max(dp[i][j-1]+grid[i][j],dp[i][j]);
                    else if(!j)
                        dp[i][j]=max(dp[i-1][j]+grid[i][j],dp[i][j]);
                    else 
                        dp[i][j]=max({dp[i-1][j]+grid[i][j],dp[i][j-1]+grid[i][j],dp[i][j]});
                }
            }
            return dp[n-1][m-1];
        }
    };
    

    第 10 天 动态规划(中等)

    剑指 Offer 46. 把数字翻译成字符串

    \(dp[i]\)表示在位置\(i\)有多少种方案,如果\(i\)\(i-1\)位置能够在一起翻译成字母,则\(dp[i]=dp[i-1]+dp[i-2]\),否则\(dp[i]=dp[i-1]\)

    点击查看代码
    class Solution {
    public:
        int dp[20];
        int translateNum(int num) {
            if(num<10)
                return 1;
            vector<int>v;
            while(num)
            {
                v.push_back(num%10);
                num/=10;
            }
            reverse(v.begin(),v.end());
            int sz=v.size();
            dp[0]=1;
            if(v[0]*10+v[1]<26)
                dp[1]=2;
            else
                dp[1]=1;
            for(int i=2;i<sz;i++)
            {
                if(v[i-1]*10+v[i]<26&&v[i-1]*10+v[i]>=10)
                    dp[i]=dp[i-1]+dp[i-2];
                else
                    dp[i]=dp[i-1];
            }
            return dp[sz-1];
        }
    };
    

    剑指 Offer 48. 最长不含重复字符的子字符串

    向后遍历,保证遍历过程中子字符串包含的字符只出现了一次。当出现第二次时,让子字符串开始的位置变成该字符出现第二次的位置。

    点击查看代码
    class Solution {
    public:
        int lengthOfLongestSubstring(string s) {
            int l=s.length();
            map<char,int>mp;
            int ans=0;
            int place=0;
            for(int i=0;i<l;i++)
            {
                if(mp[s[i]])
                    place=max(place,mp[s[i]]);
                ans=max(i-place+1,ans);
                mp[s[i]]=i+1;
            }
            return ans;
        }
    };
    

    第 11 天 双指针(简单)

    剑指 Offer 18. 删除链表的节点

    设置一个当前节点的前驱结点,如果当前节点为删除节点,停止查找,让前驱结点的下一个节点变成当前节点的下一个节点,即可实现删除

    点击查看代码
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* deleteNode(ListNode* head, int val) {
            if(head->val==val)
                return head->next;
            ListNode *pre=head,*now=head->next;
            while(now->val!=val&&now)
                pre=now,now=now->next;
            if(now)
                pre->next=now->next;
            return head;
        }
    };
    

    剑指 Offer 22. 链表中倒数第k个节点

    设置两个所指位置不同的指针,保证在前面的指针和在后面的指针相差\(k\)个节点,当在前面的指针指向链表末尾时,在后面的指针恰好指向倒数第\(k\)个节点

    点击查看代码
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* getKthFromEnd(ListNode* head, int k) {
            ListNode *slow=head,*fast=head;
            for(int i=0;i<k;i++)
            {
                if(!fast)
                    return NULL;
                fast=fast->next;
            }
            while(fast)
            {
                fast=fast->next;
                slow=slow->next;
            }
            return slow;
        }
    };
    

    第 12 天 双指针(简单)

    剑指 Offer 25. 合并两个排序的链表

    同时遍历两个链表,每次添加两个链表中较小的那个节点,知道有一个链表遍历结束

    点击查看代码
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
            ListNode *head=new ListNode(0,NULL);
            ListNode *tmp=head;
            while(l1&&l2)
            {
                if(l1->val>l2->val)
                {
                    tmp->next=l2;
                    l2=l2->next;
                }
                else
                {
                    tmp->next=l1;
                    l1=l1->next;
                }
                tmp=tmp->next;
            }
            if(l2)
                tmp->next=l2;
            if(l1)
                tmp->next=l1;
            return head->next;
        }
    };
    

    剑指 Offer 52. 两个链表的第一个公共节点

    双指针,官方题解有证明

    点击查看代码
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
            if(!headA||!headB)
                return NULL;
            ListNode *nodeA=headA,*nodeB=headB;
            while(nodeA!=nodeB)
            {
                nodeA=nodeA?nodeA->next:headB;
                nodeB=nodeB?nodeB->next:headA;
            }
            return nodeA;
        }
    };
    

    第 13 天 双指针(简单)

    剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

    两个指针分别指向数组的开头和结尾,如果左边的数为偶数,右边的数为奇数,交换两数的位置;如果左边为奇数,左指针右移;如果右边为偶数,右指针左移

    点击查看代码
    class Solution {
    public:
        vector<int> exchange(vector<int>& nums) {
            int l=0,r=nums.size()-1;
            while(l<r)
            {
                if(!(nums[l]%2)&&nums[r]%2)
                    swap(nums[l++],nums[r--]);
                else if(nums[l]%2)
                    l++;
                else if(!(nums[r]%2))
                    r--;
            }
            return nums;
        }
    };
    

    剑指 Offer 57. 和为s的两个数字

    哈希

    点击查看代码
    class Solution {
    public:
        vector<int> twoSum(vector<int>& nums, int target) {
            map<int,int>mp;
            for(auto i:nums)
            {
                if(mp[target-i])
                    return {i,target-i};
                mp[i]++;
            }
            return {};
        }
    };
    

    双指针

    点击查看代码
    class Solution {
    public:
        vector<int> twoSum(vector<int>& nums, int target) {
            int l=0,r=nums.size()-1;
            while(l<r)
            {
                if(nums[l]+nums[r]<target)
                    l++;
                else if(nums[l]+nums[r]>target)
                    r--;
                else return {nums[l],nums[r]};
            }
            return {};
        }
    };
    

    剑指 Offer 58 - I. 翻转单词顺序

    直接py

    cpp的话用栈来做吧,挺麻烦的

    点击查看代码
    class Solution:
        def reverseWords(self, s: str) -> str:
            s=s.strip().split()
            s.reverse()
            return ' '.join(s)
    
  • 相关阅读:
    线性回归和 逻辑回归 的思考(参考斯坦福 吴恩达的课程)
    数据结构算法基础-内部排序算法
    机器学习《test》
    day1.接口测试(概念、Postman、SoapUI、jmeter)
    SQL2000 3核6核 CUP 安装SP4
    SQL常用语句
    SQL SERVER 2000数据库置疑处理
    常用终端命令
    c++ 位操作
    计算机为什么用补码存储数据?
  • 原文地址:https://www.cnblogs.com/Friends-A/p/15741419.html
Copyright © 2011-2022 走看看