(一)、每日一题 2021.04.07 点击进入题目 思路:
1.暴力for。 2.二分查找。
解析: 2.二分查找 思路: 1.左中右值相等又不等于target,缩小区间:l++,r–;
2.左区间有序: (1)target在有序的区间内,范围变为:[l,mid-1] (2)target不在这段有序的区间中,范围变为:[mid+1,r]
3.右区间有序: (1)target在这段有序区间内,范围变为:[mid-1,r]; (2)target不再这段有序区间内,范围变为:[l,mid+1];
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution {public : bool search (vector <int >& nums, int target) { int n=nums.size(); if (n==0 )return false ; if (n==1 ){ if (nums[0 ]==target)return true ; else return false ; } int l=0 ; int r=n-1 ; while (l<r){ int mid=(l+r)/2 ; if (nums[mid]==target||nums[l]==target||nums[r]==target)return true ; if (nums[l]==nums[mid]&&nums[r]==nums[mid]){ l++; r--; } else if (nums[l]<=nums[mid]){ if (nums[l]<target&&nums[mid]>target) r=mid-1 ; else l=mid+1 ; } else { if (nums[r]>target&&nums[mid]<target) l=mid+1 ; else r=mid-1 ; } } return false ; } };
1.暴力for:(不是重点)
1 2 3 4 5 6 7 8 9 10 11 class Solution {public : bool search (vector <int >& nums, int target) { int n=nums.size(); for (int i=0 ;i<n;i++){ if (nums[i]==target) return true ; } return false ; } };
2021.04.08 点击进入题目 思路:
1.二分 2.暴力for
解析: 1.二分 (1)一旦nums[l]>=nums[mid]说明更小的一定在[l,mid-1]内 (2)要判断一下边界nums[l],nums[r]是不是更小的,这是用于处理有序的情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : int findMin (vector <int >& nums) { int n=nums.size(); int l=0 ; int r=n-1 ; int min=nums[0 ]; while (l<r){ int mid=l+(r-l)/2 ; if (nums[mid]<min)min=nums[mid]; if (nums[l]<min)min=nums[l]; if (nums[r]<min)min=nums[r]; if (nums[l]>=nums[mid]){ r=mid-1 ; } else { l=mid+1 ; } } return min; } };
2.暴力(懒得贴了)
2020.04.09 2020.04.10 263.丑数 点击进入题目 思路: 简单暴力。
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution {public : bool isUgly (int n) { if (n<=0 )return false ; while (n%2 ==0 ){ n=n/2 ;} while (n%3 ==0 ){ n=n/3 ;} while (n%5 ==0 ){ n=n/5 ;} if (n!=1 ) return false ; else return true ; } };
2020.04.11 264.丑数Ⅱ 点击进入题目
思路: 1.DP,三指针 2.暴力打表
解析: 1.DP,三指针 三个指针:ptr1,ptr2,ptr3 ptr1负责*2操作,ptr2负责*3操作,ptr3负责*5操作 找到每次的最小值,找到了就让指针向前跑一格 (手动模拟一遍就懂了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution {public : int nthUglyNumber (int n) { int ans[n+2 ]; ans[1 ]=1 ; int ptr1=1 ; int ptr2=1 ; int ptr3=1 ; for (int i=2 ;i<=n;i++){ int minn=min(ans[ptr1]*2 ,min(ans[ptr2]*3 ,ans[ptr3]*5 )); ans[i]=minn; if (ans[ptr1]*2 ==minn) ptr1++; if (ans[ptr2]*3 ==minn) ptr2++; if (ans[ptr3]*5 ==minn) ptr3++; } return ans[n]; } };
2.打表 适合竞赛的时候用,这里主要是DP,不贴打表做法了。
2020.04.12 179.最大数 点击进入题目
思路: 修改sort方法,将合适的位置放好,再用to_string函数拼接成答案返回
解析: 1.没有用到C++精髓的cmp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution {public : static bool cmp (int a,int b) { long sx=10 ; long sy=10 ; while (a>=sx) sx*=10 ; while (b>=sy) sy*=10 ; return sx*b+a<sy*a+b; } string largestNumber (vector <int >& nums) { sort(nums.begin(),nums.end(),cmp); string ans; for (auto num:nums) ans+=to_string(num); if (ans[0 ]=='0' )return "0" ; return ans; } };
2.用到了C++精髓的cmp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution {public : static bool cmp (int a,int b) { string x=to_string(a); string y=to_string(b); return x+y>y+x; } string largestNumber (vector <int >& nums) { sort(nums.begin(),nums.end(),cmp); string ans; for (auto num:nums) ans+=to_string(num); if (ans[0 ]=='0' )return "0" ; return ans; } };
2020.04.13 783.二叉搜索树节点最小距离 点击进入题目
思路: 1.BFS(非递归),找每个节点,用vector存起来然后sort一下,再遍历一下两两之差(代码又臭又长) (感觉需要写个stl的博客了,太不熟练) 2.官方题解①:中序遍历(递归) 3.官方题解②:莫里斯中序遍历
解析: 1.BFS: queue实现遍历每个节点,vector来存放每个节点的value,所有节点遍历完之后,对vector排个序,循环看看哪两个数的差最小就是答案了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Solution {public : int minDiffInBST (TreeNode* root) { queue <TreeNode *> roots; vector <int >ans; roots.push(root); ans.push_back(root->val); int submin=900000 ; while (!roots.empty()){ TreeNode * tmproot; tmproot=roots.front(); roots.pop(); if (tmproot->left){ roots.push(tmproot->left); ans.push_back(tmproot->left->val); } if (tmproot->right){ roots.push(tmproot->right); ans.push_back(tmproot->right->val); } } sort(ans.begin(),ans.end()); int n=ans.size(); for (int i=1 ;i<n;i++){ if (submin>ans[i]-ans[i-1 ]){ submin=ans[i]-ans[i-1 ]; } } return submin; } };
2.DFS(递归,中序遍历): 全局定义最小值,然后每次递归的时候更新最小值,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution {public : int minn=900000 ; TreeNode* pre; int minDiffInBST (TreeNode* root) { dfs(root); return minn; } void dfs (TreeNode *root) { if (root==nullptr )return ; dfs(root->left); if (pre!=nullptr ){ minn=min(minn,abs (root->val-pre->val)); } pre=root; dfs(root->right); } };
2021.04.14 208.实现Trie(前缀树) 点击进入题目
思路: 1.无敌的STL法:string + unordered_set 2.乖乖建树
题解: 1.STL法
学前缀树就知道了,可以用hash表存放串,找的时候直接通过函数找只要O(1),这里直接用unordered_set来存放;
然后用string的find函数,可以找到字串在母串哪个位置,直接字串是不是第一位就Ok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Trie {public : unordered_set <string > mode; Trie() { } void insert (string word) { mode.insert(word); } bool search (string word) { if (mode.find(word)!=mode.end())return true ; else return false ; } bool startsWith (string prefix) { for (auto s:mode){ if (s.find(prefix)==0 ) return true ; } return false ; } };
2.建树
2021.04.15 213.打家劫舍Ⅱ 点击进入题目
思路: 头取或者尾取,那么我们就开两个数组,一个存取头之后的max,一个存取尾之后的max
题解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution {public : int rob (vector <int >& nums) { int n=nums.size(); if (n==1 ) return nums[0 ]; if (n==2 ) return max(nums[1 ],nums[0 ]); int dp1[110 ]; dp1[0 ]=0 ; dp1[1 ]=nums[1 ]; int dp2[110 ]; dp2[n-1 ]=0 ; dp2[n-2 ]=nums[n-2 ]; for (int i=2 ;i<n;i++){ dp1[i]=max(dp1[i-1 ],dp1[i-2 ]+nums[i]); dp2[n-i-1 ]=max(dp2[n-i],dp2[n-i+1 ]+nums[n-i-1 ]); } return max(dp1[n-1 ],dp2[0 ]); } };
2021.04.16 87.扰乱字符串(困难) 点击进入题目
2021.04.17 220.存在重复元素Ⅲ 点击进入题目
思路: set、滑动窗口 运用set内部排序的机制,滑动窗口主要就是要准确利用合适的数据结构;窗口就是边界的处理,内部所需要的东西,需要通过不同的数据结构来实现。
解析:
eptr从小到大循环
窗口大小(即set.size())必须小于等于k,一旦比k大,左边界移一步(即从set里删除当前的sptr)
通过lower_bound()来找比nums[right]-t更大的数,如果找到了 就是true
如果循环完都没有找到,返回false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution {public : bool containsNearbyAlmostDuplicate (vector <int >& nums, int k, int t) { int n=nums.size(); if (n==0 ||n==1 ) return false ; set <long >s1; int sptr=0 ; int eptr=0 ; while (eptr<n){ if (eptr-sptr>k){ s1.erase(nums[sptr]); sptr++; } if (s1.lower_bound((long long )nums[eptr]-t)!=s1.end()&&(*(s1.lower_bound((long long )nums[eptr]-t))-nums[eptr]<=t)) return true ; s1.insert(nums[eptr]); eptr++; } return false ; } };
2021.04.18 26.删除有序数组中的重复项 点击进入题目
思路: 简单题
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution {public : int removeDuplicates (vector <int >& nums) { long n=nums.size(); for (int i=1 ;i<n;i++){ if (nums[i]==nums[i-1 ]){ nums.erase(nums.begin()+i); i--; n--; } } return n; } };
2021.04.19 27.移除元素 点击进入题目
思路: vector的erase函数,简单死了,代码都懒得放了。
2021.04.20 28.实现strStr()
不知道是不是力扣看我最近太自闭了,全是STL简单题,分分钟写出来找自信
点击进入题目
思路: string的find函数
解析:
1 2 3 4 5 6 7 class Solution {public : int strStr (string haystack, string needle) { if (haystack.find(needle)==haystack.npos) return -1 ; else return haystack.find(needle); } };
2021.04.21 91.解码方法 点击进入题目
思路: 明显DP,转移方程需要想好。 (转移方程五分钟,边界判断两小时= =)
当前单独:dp[i]=dp[i-1]
当前和前一个合并 dp[i]=dp[i-2]
选择单独或者合并 dp[i]=dp[i-1]+dp[i-2]
前导0特判:
硬判断
string前添加其他前导,使其不满足任何条件
吐槽一下“00”这个例子,必须要我手动memset一下数组,不然自己跑出来是正确的0,但是提交上去跑出来是1,WA了;日了狗!!
解析:
1.O(n)空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution {public : int numDecodings (string s) { int dp[110 ]={0 }; dp[0 ]=1 ; s=' ' +s; int a,b; int n=s.size(); for (int i=1 ;i<n;i++){ a=s[i]-'0' ; b=10 *(s[i-1 ]-'0' )+s[i]-'0' ; if (a<=9 &&a>=1 ) dp[i]=dp[i-1 ]; if (b>=10 &&b<=26 ) dp[i]=dp[i-2 ]; if (a<=9 &&a>=1 &&b>=10 &&b<=26 ) dp[i]=dp[i-1 ]+dp[i-2 ]; } return dp[n-1 ]; } };
2.空间优化O(1) 因为只用到了三个数,可以只开三位空间 循环跑这三位,通过取余操作。 主要是因为这里只用到了n-1这一位,所以dp[n-1]之前的数都是无用的,可以被不断覆盖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : int numDecodings (string s) { int dp[3 ]={0 }; dp[0 ]=1 ; s=' ' +s; int a,b; int n=s.size(); for (int i=1 ;i<n;i++){ a=s[i]-'0' ; b=10 *(s[i-1 ]-'0' )+s[i]-'0' ; dp[i%3 ]=0 ; if (a<=9 &&a>=1 ) dp[i%3 ]=dp[(i-1 )%3 ]; if (b>=10 &&b<=26 ) dp[i%3 ]=dp[(i-2 )%3 ]; if (a<=9 &&a>=1 &&b>=10 &&b<=26 ) dp[i%3 ]=dp[(i-1 )%3 ]+dp[(i-2 )%3 ]; } return dp[(n-1 )%3 ]; } };
2021.04.22 363.矩形区域不超过 K 的最大数值和【待补】 点击进入题目
写疯了,暴力肯定过不了哈。
思路: 前缀和!!(以前学过,而且第一次去比赛就用上了的差分约束,当时只有11个人写出来了,东软去的九个人全写出来了,结果我现在忘得一干二净了,菜死了无语!我甚至想用滑动窗口来解决这一题= =。) 这里是二维前缀和(我记得当时是zzy讲的)
解析:
2021.04.23 【待补】 2021.04.24 377.组合总和IV 点击进入题目
思路: 首先想到了全排列,用dfs来全排列 但是这样会TLE,要用记忆化
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution {public : int ans=0 ; unordered_map <int ,int > tmp; int combinationSum4 (vector <int >& nums, int target) { ans=dfs(target,nums); return ans; } int dfs (int target,vector <int >& nums) { if (target==0 ) return 1 ; if (target < 0 ) return 0 ; if (tmp.count(target))return tmp[target]; int step=0 ; for (int i=0 ;i<nums.size();i++){ target-=nums[i]; step+=dfs(target,nums); target+=nums[i]; } tmp[target]=step; return step; } };
2021.04.25 897.递增顺序搜索树
最近写题太懒惰了,思维也不是很好,不在状态的感觉。
思路: 中序遍历,中间进行操作。 开一个tmp,一个ans,ans指向tmp的头,最后返回的就是ans(tmp的头);
但是这里tmp开一位空的位置,空位置的right开始才是后续的答案,所以返回ans->right;
中序遍历过程中tmp的操作(已经dfs过node的left了): node的left标记为走过,不用再走了 tmp的right指向node; tmp放到tmp的right位置
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution {public : TreeNode * tmp; TreeNode * ans; TreeNode* increasingBST (TreeNode* root) { tmp=new TreeNode(-1 ); ans=tmp; dfs(root); return ans->right; } void dfs (TreeNode * node) { if (node==nullptr ) return ; dfs(node->left); node->left=nullptr ; tmp->right=node; tmp=tmp->right; dfs(node->right); } };
2021.04.26 1011.在D天内送达包裹的能力 点击进入题目
思路: 二分查找。 因为有序,能力一定是大于等于货物的最大值的。 那么就从最大值到货物总和,进行二分 看每种能力,需要的天数, 如果当前能力,送完货物的天数比D大,那么就在mid-right里,左区间可以不管了。 如果送完货物的天数比D小,那么就在left-mid,右区间不管了。
解析: left=max(nums) right=sum(nums)
需要天数直接暴力查看,然后对比D,来更新左右区间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution {public : int shipWithinDays (vector <int >& weights, int D) { int left=*max_element(weights.begin(), weights.end()); int right=accumulate(weights.begin(),weights.end(),0 ); int mid; while (right>left){ mid=left+(right-left)/2 ; int cur=0 ; int day=1 ; for (auto weight:weights){ if (cur+weight>mid){ cur=0 ; day++; } cur+=weight; } if (day<=D) right=mid; else left=mid+1 ; } return left; } };
2021.04.27 938.二叉搜索树的范围和 点击进入题目
思路: 遍历二叉树。简单题。
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution {public : int ans=0 ; int rangeSumBST (TreeNode* root, int low, int high) { dfs(root,low,high); return ans; } void dfs (TreeNode* root,int low,int high) { if (root==nullptr ){ return ; } if (root->val>=low&&root->val<=high) ans+=root->val; dfs(root->left,low,high); dfs(root->right,low,high); } };
2021.04.28 633.平方数之和 点击进入题目
思路: 根据题意,很容易想到双指针,
解析: 主要是指针如何遍历:
此题的数,a、b范围一定在[0,sqrt(c)]之间。 所以指针1(ptr1)指向0,指针2(ptr2)指向sqrt(c); 范围一定是ptr1< ptr2;(决定了外层循环) 如果两数之和,大于C,ptr2左移 如果两数之和,小于C,ptr1右移 如果等于C,返回真; 找到最后都没找到,返回FALSE;
刚开始我的思路和2,3,5那个三指针的题一样,但是那样模拟,(sqrt(c))^2+0的情况会被跳过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution {public : bool judgeSquareSum (int c) { long long ptr1=0 ; long long ptr2=sqrt (c); while (ptr1<=ptr2){ long long tmp1=ptr1*ptr1+ptr2*ptr2; if (tmp1<c)ptr1++; else if (tmp1>c)ptr2--; else return true ; } return false ; } };
2021.04.29 403.青蛙过河 点击进入题目
思路: 状态转移DP
解析:
map+set解决
map嵌套一个set,一个点,对应几个跳过去的步数(可以用哪些步数跳到) 那么可以在前面石头的时候就把后面石头的状态赋值了
dp数组转移
1.map+set
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution {public : bool canCross (vector <int >& stones) { int len=stones.size(); unordered_map <int ,unordered_set <int > > ans; ans[stones[0 ]].insert(0 ); for (int i=0 ;i<len;i++){ auto tmps=ans[stones[i]]; for (auto tmp:tmps){ for (int step=tmp-1 ;step<=tmp+1 ;step++){ ans[stones[i]+step].insert(step); } } } if (ans[stones[len-1 ]].empty()) return false ; else return true ; } };
2021.04.30 137.只出现一次的数字II 点击进入题目
思路: map,很简单,写过的。
2021.05.01 690.员工的重要性【待补】 点击进入题目
2021.05.02 554.砖墙【待补】 点击进入题目
2021.05.03 7.整数反转 点击进入题目
评论区:面试官问了这道题 然后反问面试官32位整数最大值是多少 会是什么结果
思路: 这题主要是INT_MIN和INT_MAX 用Long long 来暂存,然后对比看是否超过int。 (第一遍WA在了负数,第二遍WA在了爆INT)
解析: 直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : int reverse (int x) { string xx; xx=to_string(x); if (x<0 ){ xx.erase(xx.begin()); } int n=xx.size(); long long ans; ans=0 ; long long tmp=1 ; for (int i=0 ;i<xx.size();i++){ ans+=((xx[i]-'0' )*tmp); tmp*=10 ; } if (ans>INT_MAX||ans<INT_MIN) return 0 ; if (x<0 ) ans*=(-1 ); return ans; } };
2021.05.04 1473.粉刷房子III【待补】 点击进入题目
2021.05.05 740.删除并获得点数【待补】 点击进入题目
2021.05.06 1720.解码异或后的数组 点击进入题目
思路: 根据异或性质,很容易的出来,直接异或就好。
解析: 直接上代码:
1 2 3 4 5 6 7 8 9 10 11 class Solution {public : vector <int > decode (vector <int >& encoded, int first) { vector <int >ans; ans.push_back(first); for (int i=0 ;i<encoded.size();i++){ ans.push_back(encoded[i] xor ans.back()); } return ans; } };
2021.05.07 1486.数组异或操作 点击进入题目
思路: 简单题。
解析:
1 2 3 4 5 6 7 8 9 10 class Solution {public : int xorOperation (int n, int start) { int ans=start; for (int i=1 ;i<n;i++){ ans^=(start+i*2 ); } return ans; } };
(二)、剑指offer 58.左旋转字符串 点击进入题目
思路: 简单暴力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution {public : string reverseLeftWords (string s, int n) { int a=s.length(); string b=s; int i; for (i=0 ;i<a-n;i++){ s[i]=b[i+n]; } int j=0 ; for (;i<a;i++){ s[i]=b[j++]; } return s; } };
27.二叉树的镜像 点击进入题目
思路: 左子节点和右子节点交换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {public : TreeNode* mirrorTree (TreeNode* root) { if (root==NULL )return NULL ; TreeNode * tmp=root->left; root->left=mirrorTree(root->right); root->right=mirrorTree(tmp); return root; } };
55.二叉树的深度 点击进入题目
思路:
1.DFS 2.BFS
解析: 1.DFS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution {public : int maxDepth (TreeNode* root) { if (root==NULL )return 0 ; return 1 +max(maxDepth(root->left),maxDepth(root->right)); } };
2.BFS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution {public : int maxDepth (TreeNode* root) { if (root==NULL ) return 0 ; int depth=0 ; queue <TreeNode *> Q; Q.push(root); while (!Q.empty()){ int n=Q.size(); depth++; for (int i=0 ;i<n;i++){ TreeNode * tmp=Q.front(); Q.pop(); if (tmp->left) Q.push(tmp->left); if (tmp->right) Q.push(tmp->right); } } return depth; } };
22.链表中倒数第K个节点 点击进入题目
思路:
1.暴力得到链表长度,然后用n-k来得到倒数 2.双指针
解析: 1.暴力跑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution {public : ListNode* getKthFromEnd (ListNode* head, int k) { if (k==1 && !head->next) return head; int n=1 ; ListNode * t=head; while (t&&t->next){ n++; t=t->next; } int i; for (i=0 ;i<n;i++){ if (n-i==k) break ; else head=head->next; } return head; } };
2.双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution {public : ListNode* getKthFromEnd (ListNode* head, int k) { ListNode* first=head; ListNode* later=head; while (k--){ first=first->next; } while (first){ later=later->next; first=first->next; } return later; } };
17.打印从1到最大的n位数 点击进入题目
思路: 暴力
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {public : vector <int > printNumbers (int n) { vector <int >ans; int i=1 ; ans.push_back(i); while (i++){ int num=1 ; int tmp=i; while (tmp/10 ){ num++; tmp/=10 ; } if (num>n) break ; ans.push_back(i); } return ans; } };
29.顺时针打印矩阵 点击进入题目
思路: 注意边界,循环跑
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution {public : vector <int > spiralOrder (vector <vector <int >>& matrix) { if (matrix.size() == 0 ) return {}; vector <int > ans; if (matrix[0 ].size()==0 ) return ans; int left=0 ; int right=matrix[0 ].size()-1 ; int top=0 ; int bottom=matrix.size()-1 ; while (left<=right&&top<=bottom){ for (int i=left;i<=right;i++){ ans.push_back(matrix[top][i]); } for (int i=top+1 ;i<=bottom;i++){ ans.push_back(matrix[i][right]); } if (left<right&&top<bottom){ for (int i=right-1 ;i>=left;i--){ ans.push_back(matrix[bottom][i]); } for (int i=bottom-1 ;i>top;i--){ ans.push_back(matrix[i][left]); } } right--; left++; bottom--; top++; } return ans; } };
05.替换空格 点击进入题目
思路: 知识点就是正确使用string,string直接拼接就完事,很简单
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution {public : string replaceSpace (string s) { string ans; int n=s.size(); for (int i=0 ;i<n;i++){ if (s[i]!=' ' ){ ans+=s[i]; } else { ans+="%20" ; } } return ans; } };
06.从头到尾打印链表 点击进入题目
思路: 很傻一道题,把链表的数用vector存下来,用个reverse函数翻转一下就ok。
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution {public : vector <int > reversePrint (ListNode* head) { vector <int >ans; if (head==NULL ) return ans; int i=0 ; while (head){ ans.push_back(head->val); head=head->next; } reverse(ans.begin(),ans.end()); return ans; } };
54.二叉搜索树的第K大节点 点击进入题目
思路: set能排序,就很舒服,直接用dfs把所有数存在set里,然后返回set。
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution {public : set <int > tmp; int kthLargest (TreeNode* root, int k) { dfs(root); int n=tmp.size(); return *tmp.begin()+(n-k); } void dfs (TreeNode *root) { if (root==NULL )return ; tmp.insert(root->val); dfs(root->left); dfs(root->right); } };
24.反转链表 深刻认识到链表相关的知识掌握得太薄弱了。
15.二进制中1的个数 点击进入题目
思路: 注意虽然给的是一串数字,但是是二进制 ,所以除的时候不是除以十,是右移1位 ,所以是除以二。
解析:
1 2 3 4 5 6 7 8 9 10 11 12 class Solution {public : int hammingWeight (uint32_t n) { long long ans=0 ; while (n){ if (n%2 ==1 ) ans++; n>>=1 ; } return ans; } };
25.合并两个排序的链表 思路:
解析:
49.丑数 二刷丑数Ⅱ 点击进入题目
思路: 三指针、DP
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution {public : int nthUglyNumber (int n) { long long uglys[2000 ]; int ptr1=1 ; int ptr2=1 ; int ptr3=1 ; uglys[1 ]=1 ; for (int i=2 ;i<=n;i++){ uglys[i]=min(uglys[ptr1]*2 ,min(uglys[ptr2]*3 ,uglys[ptr3]*5 )); if (uglys[ptr1]*2 ==uglys[i]){ ptr1++; } if (uglys[ptr2]*3 ==uglys[i]){ ptr2++; } if (uglys[ptr3]*5 ==uglys[i]){ ptr3++; } } return uglys[n]; } };
59-I.滑动窗口的最大值 点击进入题目
第一个没有看题解写出来的困难题,嘎嘎嘎无敌!! (看了评论区,好吧,我是废物)
思路: 滑动窗口+multiset用set有坑 ,因为窗口内会有重复的元素 !! 用set的话,如果窗口的left是重复元素之一,erase(nums[left])的时候会擦掉窗口内的元素! 咱用mutiset(再夸一下,STL无敌!!),然而!multiset的erase也有误用情况!因为erase都是擦除全部,得用迭代器来找(不用多说,很好理解吧!),然后erase掉迭代器的位置。
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution {public : vector <int > maxSlidingWindow (vector <int >& nums, int k) { multiset <int > tmp; vector <int > ans; int left=0 ; int right=0 ; int n=nums.size(); if (nums.size()==0 ) return ans; while (right<n){ if (right-left>k){ multiset <int >::iterator pos = tmp.find(nums[left]); tmp.erase(pos); left++; } if (right-left==k){ int nn=tmp.size(); ans.push_back(*tmp.rbegin()); } tmp.insert(nums[right]); right++; } tmp.insert(nums[right-1 ]); if (right-left>k){ multiset <int >::iterator pos = tmp.find(nums[left]); tmp.erase(pos); left++; } if (right-left==k){ int nn=tmp.size(); ans.push_back(*tmp.rbegin()); } return ans; } };
10-Ⅱ.青蛙跳台阶问题 点击进入题目
思路: = =入门的,没啥好说的。
解析:
1 2 3 4 5 6 7 8 9 10 11 12 class Solution {public : int numWays (int n) { int ans[110 ]; ans[0 ]=1 ; ans[1 ]=1 ; ans[2 ]=2 ; for (int i=3 ;i<=n;i++) ans[i]=(ans[i-1 ]+ans[i-2 ])%1000000007 ; return ans[n]; } };
53-Ⅱ.0~n-1中缺失的数字 点击进入题目
简单题,O(n)和O(logn)都可过。
思路: 评论区一位大佬曰:“排序这个条件没用上的可以不用秀了。”搞得我都不好意思不用二分写一下了。
解析:
O(n)遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution {public : int missingNumber (vector <int >& nums) { int i; for (i=0 ;i<nums.size();i++){ if (nums[i]!=i){ break ; } } return i; } };
O(logn)二分查找:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution {public : int missingNumber (vector <int >& nums) { int l=0 ; int r=nums.size()-1 ; int mid=(l+r)/2 ; while (l<=r){ mid=(l+r)/2 ; if (nums[mid]!=mid) r=mid-1 ; else l=mid+1 ; } return l; } };
56-Ⅱ.数组中数字出现的次数Ⅱ 点击进入题目
思路: 1.用STL:MAP或者直接count(),美汁汁儿! 2.状态机:位运算;但是是数电的东西,没学过,先不慌写
解析: 1.Map:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution {public : int singleNumber (vector <int >& nums) { map <int ,int > ans; int ansnum; for (int i=0 ;i<nums.size();i++){ ans[nums[i]]++; } for (int i=0 ;i<nums.size();i++){ if (ans[nums[i]]==1 ){ ansnum=nums[i]; } } return ansnum; } };
2.状态机:位运算
61.扑克牌中的顺子
说实话,这题真的恶心人,不知道在干嘛。he tui!!真的是不想看得很,又害怕到时候我撞上了这sb题,大草,认怂。之前cf开的一个打麻将的顺子筒子啥的题,比这好了不止10倍!我tm直接给这题出题人上香!!
16.数值的整数次方 点击进入题目
这题就该用pow,返回值是double,也没有取模,完全就是pow,有点委屈快速幂了。
思路:
pow()
快速幂。
解析:
1.pow()
1 2 3 4 5 6 class Solution {public : double myPow (double x, int n) { return pow (x,n); } };
2.快速幂:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution {public : double myPow (double x, int n) { double ans=1.0 ; int tmp=abs (n); while (tmp){ if (tmp&1 ){ ans*=x; } x=x*x; tmp=tmp/2 ; } if (n<0 )return 1 /ans; return ans; } };
(三)、题库 198.打家劫舍 点击进入题目
思路: 很easy的dp,偷还是不偷两种选择 公式:dp[n]=max(dp[n-1],dp[n-1]+nums[i]);
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution {public : int rob (vector <int >& nums) { long dp[1010 ]; if (nums.size()==1 ) return nums[0 ]; dp[0 ]=nums[0 ]; dp[1 ]=max(nums[1 ],nums[0 ]); for (int i=2 ;i<nums.size();i++){ dp[i]=max(dp[i-1 ],dp[i-2 ]+nums[i]); } return dp[nums.size()-1 ]; } };
3.无重复字符的最长字串 点击进入题目
思路: 入门级滑动窗口。
解析:
开个hashmap来存字母出现次数
左右指针中,右指针向右遍历
遍历过程中如果当前字母是之前出现过的,就找到之前出现的位置,把左值针指向找到的位置,缩小窗口 在循环中不断更新ans。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution {public : int lengthOfLongestSubstring (string s) { int ans=0 ; int n=s.size(); if (n==0 ) return 0 ; if (n==1 ) return 1 ; unordered_map <char , int > ss; int sptr=0 ; int eptr=0 ; while (eptr<n){ char c1=s[eptr++]; ss[c1]++; while (ss[c1]>1 ){ char c2=s[sptr]; ss[c2]--; sptr++; } ans=max(ans,eptr-sptr); } return ans; } };
875.爱吃香蕉的珂珂 点击进入题目
思路: 二分查找,边界注意。
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {public : int minEatingSpeed (vector <int >& piles, int h) { int left=1 ; int right=*max_element(piles.begin(),piles.end()); int mid; while (left<right){ mid=left+(right-left)/2 ; int time=0 ; for (auto pile:piles){ time=time+(pile)/mid; if (pile%mid!=0 ) time++; } if (time>h)left=mid+1 ; else right=mid; } return left; } };