##每日一题##

根据前序遍历和中序遍历构造二叉树

思路:从性质出发,前序数组的开头就是根节点,然后对应到中序数组,得到左子树和右子树,分别再构造左子树和右子树

下标对应:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hrGX1T3d-1595485102474)(C:\Users\86178\Desktop\力扣\图片\2020-05-22_085059.png)]

优化:

将中序数组存入哈希表,方便找到对用的下标

#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>using namespace std;struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}};class Solution {
public:unordered_map<int,int> map;TreeNode* create(vector<int>& preorder,int preLeft,int preRight,int inLeft,int inRight){if(preLeft>preRight || inLeft>inRight)return NULL;int rootVal=preorder[preLeft];TreeNode* root=new TreeNode(rootVal);int index=map[rootVal];root->left=create(preorder,preLeft+1,preLeft+index-inLeft,inLeft,index-1);root->right=create(preorder,preLeft+index-inLeft+1,preRight,index+1,inRight);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {int preLen=preorder.size();int inLen=inorder.size();TreeNode* root;for (int i = 0; i < inLen; ++i) {map.insert({inorder[i],i});}return create(preorder,0,preLen-1,0,inLen-1);}
};

寻找两个正序数组的中位数

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。

请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

nums1 = [1, 3]
nums2 = [2]则中位数是 2.0nums1 = [1, 2]
nums2 = [3, 4]则中位数是 (2 + 3)/2 = 2.5

归并排序的思路

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int length1 = nums1.size();int length2 = nums2.size();int i,j,k;vector<int> temp(length1+length2, 0);for(i=0,j=0,k=0;i<length1 && j<length2;k++){if(nums1[i]<nums2[j]){temp[k] = nums1[i];i++;}else{temp[k] = nums2[j];j++;}}while(i<length1)temp[k++]=nums1[i++];while(j<length2)temp[k++]=nums2[j++];if((length1+length2)%2 ==1)return temp[(length1+length2)/2];elsereturn (temp[(length1+length2)/2]+temp[(length1+length2)/2-1])/2.0;}
};

二分查找的思路

太麻烦了

class Solution {
public:int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {/* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较* 这里的 "/" 表示整除* nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个* nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个* 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个* 这样 pivot 本身最大也只能是第 k-1 小的元素* 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组* 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组* 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数*/int m = nums1.size();int n = nums2.size();int index1 = 0, index2 = 0;while (true) {// 边界情况if (index1 == m) {return nums2[index2 + k - 1];}if (index2 == n) {return nums1[index1 + k - 1];}if (k == 1) {return min(nums1[index1], nums2[index2]);}// 正常情况int newIndex1 = min(index1 + k / 2 - 1, m - 1);int newIndex2 = min(index2 + k / 2 - 1, n - 1);int pivot1 = nums1[newIndex1];int pivot2 = nums2[newIndex2];if (pivot1 <= pivot2) {k -= newIndex1 - index1 + 1;index1 = newIndex1 + 1;}else {k -= newIndex2 - index2 + 1;index2 = newIndex2 + 1;}}}double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int totalLength = nums1.size() + nums2.size();if (totalLength % 2 == 1) {return getKthElement(nums1, nums2, (totalLength + 1) / 2);}else {return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;}}
};

上一题的前导问题的多种解法(合并两个有序数组)

给你两个有序整数数组 nums1nums2,请你将 nums2 合并到 nums1 中*,*使 nums1 成为一个有序数组。

从前到后

class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {vector<int> temp(nums1);int i,j,k;for (i=0,j=0, k = 0; i<m && j<n ; ++k) {if(temp[i]<=nums2[j]){nums1[k]=temp[i];i++;} else{nums1[k]=nums2[j];j++;}}while (i<m)nums1[k++]=temp[i++];while (j<n)nums1[k++]=nums2[j++];}
};

从后到前

class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int i=m-1,j=n-1,k=m+n-1;while (i>=0 && j>=0){if(nums1[i]>nums2[j])nums1[k--]=nums1[i--];elsenums1[k--]=nums2[j--];}while (j>=0)nums1[k--]=nums2[j--];while (i>=0)nums1[k--]=nums1[i--];}
};

排序

class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {for(auto x:nums2){nums1[m++]=x;}sort(nums1.begin(),nums1.end());}
};

287. 寻找重复数

给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。输入: [1,3,4,2,2]
输出: 2说明:不能更改原数组(假设数组是只读的)。
只能使用额外的 O(1) 的空间。
时间复杂度小于 O(n2) 。
数组中只有一个重复的数字,但它可能不止重复出现一次。

直接用set处理

class Solution {
public:int findDuplicate(vector<int>& nums) {unordered_set<int> set;for (int i = 0; i < nums.size(); ++i) {if(set.find(nums[i])!=set.end())return nums[i];set.insert(nums[i]);}return -1;}
};

快慢指针

class Solution {
public:int findDuplicate(vector<int>& nums) {int slow=0;int fast=0;while(1){slow=nums[slow];fast=nums[nums[fast]];if(slow==fast){fast=0;while(1){if(fast==slow)return slow;slow=nums[slow];fast=nums[fast];}}}}
};

二分法

预备知识:抽屉原理:桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面放不少于两个苹果。

class Solution {
public:int findDuplicate(vector<int>& nums) {int left=1;int right=nums.size()-1;while(left<right){int mid=left+(right-left)/2;int count=0;for(auto x:nums){if(x<=mid)count++; //小于mid的数,例如小于4的数是1,2,3,4}if(count>mid) //如果大于等于4个 那么重复元素一定在[1,4]的的区间right=mid;elseleft=mid+1;}return left;}
};

394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

s = "3[a]2[bc]", 返回 "aaabcbc".
s = "3[a2[c]]", 返回 "accaccacc".
s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".
class Solution {
public:string decodeString(string s) {string res;int count = 0;int left,right,lr=0;for(int i=0;i<s.size();i++){if('a'<=s[i] && s[i]<='z'||'A'<=s[i] && s[i]<='Z'){if(count==0)res.push_back(s[i]);}else if('0'<=s[i]&&s[i]<='9'){if(lr==0)count = 10*count + (s[i] - '0'); //统计重复次数}else if(s[i]=='['){if(lr==0) //遇到第一个 '['left=i;lr++;}else if(s[i]==']'){lr--;if(lr==0){ // 遇到最后一个 ']'right=i;while(count>0){res += decodeString(s.substr(left+1,right-left-1));count--;}}}}return res;}
};

101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。1
/ \
2   2
/ \ / \
3  4 4  3但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:1
/ \
2   2
\   \
3    3

思路:镜像对称的二叉树要求 一个树的左子树与右子树镜像对称,那么这个树是对称的。

​ 那么两个树在什么情况下互为镜像?

​ 1、他们两个根节点的值相同

​ 2、每个树的左子树和另一棵树的右子树镜像对称

class Solution {
public:bool check(TreeNode* leftRoot,TreeNode* rightRoot){if(leftRoot==NULL && rightRoot==NULL) //两个都为空肯定对称return true;if(leftRoot==NULL || rightRoot==NULL)//一个空 一个不空肯定不对称return false;return (leftRoot->val==rightRoot->val) && check(leftRoot->left,rightRoot->right) && check(leftRoot->right,rightRoot->left); //只有1、他们两个根节点的值相同 2、每个树的左子树和另一棵树的右子树镜像对称  才是对称的}bool isSymmetric(TreeNode* root) {return check(root,root);}
};

238. 除自身以外数组的乘积

给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。

输入: [1,2,3,4]
输出: [24,12,8,6]

嘿嘿

思路就是计算左边 计算右边 乘一下

class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {int sum=1;vector<int> res;int left[nums.size()];int right[nums.size()];left[0]=1;for (int i = 1; i < nums.size(); ++i) {left[i]=left[i-1]*nums[i-1];}right[nums.size()-1]=1;for (int i = nums.size()-2; i >=0; --i) {right[i]=right[i+1]*nums[i+1];}for (int i = 0; i < nums.size(); ++i) {res.push_back(left[i]*right[i]);}return res;}
};

大佬的精简代码

class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {int sum=1;vector<int> res(nums.size(),1);vector<int> left(nums.size(),1);vector<int> right(nums.size(),1);for (int i = 0; i < nums.size(); ++i) {left[i]*=sum;sum*=nums[i];}sum=1;for (int i = nums.size()-1; i >=0; --i) {right[i]*=sum;sum*=nums[i];res[i]=left[i]*right[i];}return res;}
};

面试题29. 顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

模拟

class Solution {
public:vector<int> spiralOrder(vector<vector<int>>& matrix) {vector<int> res;if(matrix.size()==0)return res;int x=0,y=0;vector<vector<int>> visited(matrix.size(),vector<int>(matrix[0].size(),0));res.push_back(matrix[0][0]);visited[0][0]=1;while(res.size()<matrix.size()*matrix[0].size()){while(y+1<matrix[0].size() && !visited[x][y+1]){res.push_back(matrix[x][++y]);visited[x][y]=1;}while(x+1<matrix.size() && !visited[x+1][y]){res.push_back(matrix[++x][y]);visited[x][y]=1;}while(y-1>=0 && !visited[x][y-1]){res.push_back(matrix[x][--y]);visited[x][y]=1;}while(x-1>=0 && !visited[x-1][y]){res.push_back(matrix[--x][y]);visited[x][y]=1;}}return res;}
};

128. 最长连续序列

给定一个未排序的整数数组,找出最长连续序列的长度。

要求算法的时间复杂度为 O(n)

输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。

哈希法

思路: 重复元素就很烦,先用set去重,然后用set也方便查看序列是否包含某个元素

​ 1、核心思路是对于每个元素x查看x+1,x+2…x+y是否存在,并且在断链之后更新res

​ 但是这样的话极端情况下,复杂度会到N^2

​ 继续思考,其实没必要对于每个元素都查看一下的,对于元素链上的每一个元素 其实都已经在产生了对应的currRes 所以 1操作加以限制

class Solution {
public:int longestConsecutive(vector<int>& nums) {if(nums.size()==0){return 0;}unordered_set<int> num_set;for(auto x:nums)num_set.insert(x);int res=0;for (auto x:num_set) {if(!num_set.count(x-1)){int currNum=x;int currRes=1;while(num_set.count(currNum+1)){currNum++;currRes++;}res=max(res,currRes);}}return res;}
};

并查集

思路:

  1. 初始化的时候先把数组里每个元素初始化为他的下一个数;
  2. 并的时候找他能到达的最远的数字就可以了。
  3. 太强了
class Solution {
public:unordered_map<int,int> a;int find(int x){return a.count(x)?a[x]=find(a[x]):x;}int longestConsecutive(vector<int>& nums) {for(auto i:nums)a[i]=i+1;int ans=0;for(auto i:nums){int y=find(i+1);ans=max(ans,y-i);}return ans;}
};

面试题46. 把数字翻译成字符串

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"

动态规划

class Solution {
public:int translateNum(int num) {string strNum=to_string(num);vector<int> dp(strNum.size()+1,0);dp[0]=1;dp[1]=1;for (int i = 2; i < dp.size(); ++i) {dp[i]+=dp[i-1];if(strNum[i-2]!='1' && strNum[i-2]!='2')continue;if(strNum[i-2]=='2' && strNum[i-1]>'5')continue;dp[i]+=dp[i-2];}return dp[strNum.size()];}
};

滑窗

739. 每日温度

根据每日 气温 列表,请重新生成一个列表,对应位置的输出是需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

单调栈

class Solution {
public:vector<int> dailyTemperatures(vector<int>& T) {int n=T.size();vector<int> res(n);stack<int> stack;for (int i = 0; i < n; ++i) {while(!stack.empty() && T[i]>T[stack.top()]){auto top=stack.top();res[top]=i-top;stack.pop();}stack.push(i);}return res;}
};

1300. 转变数组后最接近目标值的数组和

给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近 target (最接近表示两者之差的绝对值最小)。

如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。

请注意,答案不一定是 arr 中的数字。

输入:arr = [4,9,3], target = 10
输出:3
解释:当选择 value 为 3 时,数组会变成 [3, 3, 3],和为 9 ,这是最接近 target 的方案。

暴力解决

思路:先排序,接着就是遍历,维系一个sumLeft 是之前已经判断过的数,sum是sumLeft+以当前数为value 的一个结果,若是sum>=target则,这是一个可行解,且由于经过了排序,这就是所求解

接着计算这个value的确切值

class Solution {
public:int findBestValue(vector<int>& arr, int target) {sort(arr.begin(), arr.end());int n = arr.size();int sumLeft = 0;for(int i = 0; i < n; i ++){int sum = sumLeft + arr[i] * (n - i);if(sum >= target){double ans = (double)((target - sumLeft)/(n - i));if(ans-sum<=0.5)return ans;return ans + 1;}sumLeft += arr[i];}return 0;}
};

14. 最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""

输入: ["flower","flow","flight"]
输出: "fl"

暴力

class Solution {
public:string longestCommonPrefix(vector<string>& strs) {string res;if(!strs.size())return res;else if(strs.size()==1)return strs[0];int n=strs.size();int i=0;while(1){char temp=strs[0][i];for (int j = 1; j < n; ++j) {if(i>=strs[i].size())return res;if(strs[j][i]!=temp)return res;}res+=temp;i++;}}
};

暴力优化

排序完就比较头和尾就好了

class Solution {
public:string longestCommonPrefix(vector<string>& strs) {if(strs.empty())return string();sort(strs.begin(),strs.end());string begin=strs.front(),end=strs.back();int i,num=min(begin.size(),end.size());for (i = 0; i <num && begin[i]==end[i] ; ++i) ;return string(begin,0,i);}
};

水平扫描

先将第一个元素作为最长前缀,然后不断地将这个最长前缀和后面地元素匹配(缩短它),最后将结果输出

若最长前缀再某一次为空,则直接返回空就好了

class Solution {
public:string longestCommonPrefixInTwo(string s1,string s2){int i;for (i = 0; i < min(s1.size(), s2.size()) && s1[i] == s2[i]; ++i);return s1.size()>s2.size()?string(s2,0,i):string(s1,0,i);}string longestCommonPrefix(vector<string>& strs) {if(strs.empty())return string();string res=strs[0];for (int i = 1; i < strs.size(); ++i) {res=longestCommonPrefixInTwo(res,strs[i]);if(res.size()==0)return res;}return res;}
};

分治法

class Solution {
public:string longestCommonPrefixInTwo(string s1,string s2){int i;for (i = 0; i < min(s1.size(), s2.size()) && s1[i] == s2[i]; ++i);return s1.size()>s2.size()?string(s2,0,i):string(s1,0,i);}string divide(vector<string>& strs,int start,int end){if(start==end)return strs[start];int mid=(start+end)/2;string left=divide(strs,start,mid);string right=divide(strs,mid+1,end);return longestCommonPrefixInTwo(left,right);}string longestCommonPrefix(vector<string>& strs) {if(strs.empty())return string();elsereturn divide(strs,0,strs.size()-1);}
};

二分法

思路:先找到元素集合地最短长度,因为这个长度就是前缀最理想状况下的长度

因为最长前缀是公共的 所以就直接拿第一个元素来用

不断地看第一个元素的左区间是不是符合要求,是的话就去右区间找找,

​ 不符合要求的话就是抛弃右区间

class Solution {
public:bool isCommonPrefix(vector<string>& strs,int length){string target=strs[0].substr(0,length);for (int i = 1; i < strs.size(); ++i) {string cur=strs[i];for (int j = 0; j < length; ++j) {if(target[j]!=cur[j])return false;}}return true;}string longestCommonPrefix(vector<string>& strs) {if(strs.empty())return string();int left=0;int right=INT_MAX;for (int i = 0; i < strs.size(); ++i) {if(strs[i].size()<right)right=strs[i].size();}while(left<right){int mid=(right-left+1)/2+left;if(isCommonPrefix(strs,mid)) //mid之前是前缀,去mid后面找left=mid;else                          //mid之前不是前缀,在mid区间里面找right=mid-1;}return strs[0].substr(0,left);}
};

125. 验证回文串

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

**说明:**本题中,我们将空字符串定义为有效的回文串。

输入: "A man, a plan, a canal: Panama"
输出: true
class Solution {
public:bool isPalindrome(string s) {for (int i = 0; i < s.size(); ++i) {s[i]=tolower(s[i]);}int i=0;int j=s.size()-1;while(i<j){while(s[i]==' ' || s[i]<'a' || s[i]>'z')i++;while(s[j]==' ' || s[j]<'a' || s[j]>'z')j--;if(s[i]!=s[j])return false;i++;j--;}return true;}
};

帅气双指针

class Solution {
public:bool isPalindrome(string s) {string str;for (int i = 0; i < s.size(); ++i) {if(isalpha(s[i]))str.push_back(tolower(s[i]));}int left=0;int right=str.size()-1;while(left<right){if(str[left]!=str[right])return false;left++;right--;}return true;}
};

帅气+1

class Solution {
public:bool isPalindrome(string s) {string str;for (int i = 0; i < s.size(); ++i) {if(isalpha(s[i]))str.push_back(tolower(s[i]));}string str_re(str.rbegin(),str.rend());return str_re==str;}
};

309. 最佳买卖股票时机含冷冻期

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]

动态规划

class Solution {
public:int maxProfit(vector<int>& prices) {if (prices.empty())return 0;int n=prices.size();int dp[n][3];dp[0][0]=0;//不持股dp[0][1]=-prices[0];//持股dp[0][2]=0;//冰冻期for (int i = 1; i < n; ++i) {dp[i][0]=max(dp[i-1][0],dp[i-1][2]); //第i天不持股可以从两种状态转移过来,第i-1天不持股或者是冰冻期(如果是持股的话应该是冰冻期而不是不持股地状态)dp[i][1]=max(dp[i-1][0]-prices[i],dp[i-1][1]);//第i天持股可以从两种状态转移过来,第i-1天不持股,但是今天买入;第i-1天处于冰冻期,但是今天买入;dp[i][2]=dp[i-1][1]+prices[i];//第i天冰冻期,只有一种情况就是i-1天持股,第i天卖出}return max(dp[n-1][0],dp[n-1][2]);//倒数第二天不持股或者处于冰冻期才能取最大值}
};

空间优化

class Solution {
public:int maxProfit(vector<int>& prices) {if (prices.empty())return 0;int n=prices.size();int a=0,b=-prices[0],c=0;int aa,bb,cc;for (int i = 1; i <n ; ++i) {//a是不持股票//b是持有股票//c是冰冻期aa=max(a,c);bb=max(a-prices[i],b);cc=b+prices[i];a=aa;b=bb;c=cc;}return max(a,c);}
};

350. 两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]

哈希表

class Solution {
public:vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {vector<int> res;if(nums1.empty() || nums2.empty())return res;unordered_map<int,int> map;for(int i=0;i<nums1.size();i++){if(map[nums1[i]]){map[nums1[i]]++;}else{map[nums1[i]]=1;}}for(int i=0;i<nums2.size();i++){if(map[nums2[i]] || map[nums2[i]]>0){map[nums2[i]]--;res.push_back(nums2[i]);}}return res;}
};

排序

class Solution {
public:vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {vector<int> res;if(nums1.empty() || nums2.empty())return res;sort(nums1.begin(),nums1.end());sort(nums2.begin(),nums2.end());int i=0,j=0;while(i<nums1.size() && j<nums2.size()){if(nums1[i]==nums2[j]){res.push_back(nums1[i]);i++;j++;}else if(nums1[i]<nums2[j]){i++;}else{j++;}}return res;}
};

120. 三角形最小路径和

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。

例如,给定三角形:

[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

动态规划

/** dp[i][j]表示到(i,j)的最小路径和* */
class Solution {
public:int minimumTotal(vector<vector<int>>& triangle) {int n=triangle.size();vector<vector<int>> dp(n, vector<int>(n));dp[0][0]=triangle[0][0];for (int i = 1; i <n ; ++i) {dp[i][0]=dp[i - 1][0] + triangle[i][0];for (int j = 1; j <i ; ++j) {dp[i][j]=min(dp[i-1][j-1],dp[i-1][j])+triangle[i][j];}dp[i][i]=dp[i - 1][i-1] + triangle[i][i];}return *min_element(dp[n-1].begin(),dp[n-1].end());}
};

动态规划 降秩

思路上和大大背包9讲的降秩一样

class Solution {
public:int minimumTotal(vector<vector<int>>& triangle) {int n=triangle.size();vector<int> dp(n);dp[0]=triangle[0][0];for (int i = 1; i <n ; ++i) {dp[i]=dp[i - 1] + triangle[i][i];for (int j = i-1; j >0 ; --j) {dp[j]=min(dp[j-1],dp[j])+triangle[i][j];}dp[0]+= triangle[i][0];}return *min_element(dp.begin(),dp.end());}
};

785. 判断二分图

给定一个无向图graph,当这个图为二分图时返回true。

如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。

graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值。

示例 1:
输入: [[1,3], [0,2], [1,3], [0,2]]
输出: true
解释:
无向图如下:
0----1
| |
| |
3----2
我们可以将节点分成两组: {0, 2} 和 {1, 3}。

示例 2:
输入: [[1,2,3], [0,2], [0,1,3], [0,2]]
输出: false
解释:
无向图如下:
0----1
| \ |
| \ |
3----2
我们不能将节点分割成两个独立的子集

记忆化DFS(染色法)

class Solution {
public:bool dfs(vector<vector<int>>& graph,vector<int>& tag,int index,int color){ //判断第index个节点能否被染为color色(1 0)if(tag[index]!=-1)return tag[index]==color; //当前节点已染色 判断染色是否正常tag[index]=color;for (auto node:graph[index]) { //为相邻节点染相反色if(!dfs(graph,tag,node,!color))return false;}return true;}bool isBipartite(vector<vector<int>>& graph) {int n=graph.size();vector<int> tag(n,-1); //-1表示未染色 染成0 1for (int i = 0; i < n; ++i) {if(tag[i]==-1 && !dfs(graph,tag,0,0))return false;}return true;}
};

BFS

class Solution {
public:bool isBipartite(vector<vector<int>>& graph) {int n=graph.size();vector<int> tag(n,-1); //-1表示未染色 染成0 1queue<int> q;for (int i = 0; i < n; ++i) {if(tag[i]==-1){q.push(i);tag[i]=0;while(!q.empty()){int  node= q.front();int color=!tag[node];q.pop();for(auto x:graph[node]){if(tag[x]==-1){q.push(x);tag[x]=color;}else if(tag[x]!=color)return false;}}}}return true;}
};

35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5
输出: 2
示例 2:

输入: [1,3,5,6], 2
输出: 1
示例 3:

输入: [1,3,5,6], 7
输出: 4
示例 4:

输入: [1,3,5,6], 0
输出: 0

二分查找

class Solution {
public:int searchInsert(vector<int>& nums, int target) {int n=nums.size();if(n==0)return 0;if(nums[n-1]<target)return n;int i=0,j=n-1;while(i<j){int mid=i+(j-i)/2;if(nums[mid]==target)return mid;else if(nums[mid]<target)i=mid+1;else   j=mid;}return i;}
};

64. 最小路径和

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

示例:

输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小

帅气动态规划

class Solution {
public:int minPathSum(vector<vector<int>>& grid) {int m=grid.size();int n=grid[0].size();int dp[m][n];dp[0][0]=grid[0][0];for(int i=0;i<m;i++){for(int j=0;j<n;j++){if(i==0 && j==0)continue;else if(i==0)dp[i][j]=dp[i][j-1]+grid[i][j];else if(j==0)dp[i][j]=dp[i-1][j]+grid[i][j];elsedp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];}}return dp[m-1][n-1];}
};

帅气降秩

class Solution {
public:int minPathSum(vector<vector<int>>& grid) {int m=grid.size();int n=grid[0].size();int dp[n];dp[0]=grid[0][0];for(int i=1;i<n;i++){dp[i]=dp[i-1]+grid[0][i];}for(int i=1;i<m;i++){dp[0]=dp[0]+grid[i][0];for (int j = 1; j < n; ++j) {dp[j]=min(dp[j-1],dp[j])+grid[i][j];}}return dp[n-1];}
};

LeetCode每日一题系列 随缘更新相关推荐

  1. leetcode每日一题系列——787. K 站中转内最便宜的航班

    787. K 站中转内最便宜的航班 难度中等346收藏分享切换为英文接收动态反馈 有 n 个城市通过一些航班连接.给你一个数组 flights ,其中 flights[i] = [fromi, toi ...

  2. leetcode每日一题系列——881. 救生艇

    881. 救生艇 难度中等166收藏分享切换为英文接收动态反馈 第 i 个人的体重为 people[i],每艘船可以承载的最大重量为 limit. 每艘船最多可同时载两人,但条件是这些人的重量之和最多 ...

  3. leetcode每日一题系列——797. 所有可能的路径

    797. 所有可能的路径 难度中等185收藏分享切换为英文接收动态反馈 给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序) 二维数 ...

  4. LeetCode每日一题(持续更新中~~~)

    文章目录 2432. 处理用时最长的那个任务的员工5.5 1419. 数青蛙5.6 1010. 总持续时间可被 60 整除的歌曲5.7 2432. 处理用时最长的那个任务的员工5.5 共有 n 位员工 ...

  5. LeetCode每日一题——1235. 规划兼职工作

    LeetCode每日一题系列 题目:1235. 规划兼职工作 难度:困难 文章目录 LeetCode每日一题系列 题目 示例 思路 题解 题目 你打算利用空闲时间来做兼职工作赚些零花钱. 这里有 n ...

  6. LeetCode每日一题——1812. 判断国际象棋棋盘中一个格子的颜色

    LeetCode每日一题系列 题目:1812. 判断国际象棋棋盘中一个格子的颜色 难度:简单 文章目录 LeetCode每日一题系列 题目 示例 思路 题解 题目 给你一个坐标 coordinates ...

  7. LeetCode每日一题——904. 水果成篮

    LeetCode每日一题系列 题目:904. 水果成篮 难度:普通 文章目录 LeetCode每日一题系列 题目 示例 思路 题解 题目 你正在探访一家农场,农场从左到右种植了一排果树.这些树用一个整 ...

  8. LeetCode每日一题——1758. 生成交替二进制字符串的最少操作数

    LeetCode每日一题系列 题目:1758. 生成交替二进制字符串的最少操作数 难度:简单 文章目录 LeetCode每日一题系列 题目 示例 思路 题解 题目 给你一个仅由字符 '0' 和 '1' ...

  9. LeetCode每日一题——927. 三等分

    LeetCode每日一题系列 题目:927. 三等分 难度:困难 文章目录 LeetCode每日一题系列 题目 示例 思路 题解 题目 给定一个由 0 和 1 组成的数组 arr ,将数组分成 3 个 ...

最新文章

  1. Flutter开发之Scaffold 脚手架的使用(39)
  2. 2019~2020这个时间段适合买房吗?
  3. JAVA----------------------华为机试--------------------------删除字符串中出现次数最少的字符...
  4. 禁用当前的账户win7_拯救你的win7系统,电脑优化到位,打游戏才会流畅
  5. sonar:默认的扫描规则
  6. web 折线图大数据量拉取展示方案_分布式、服务化的企业级 ERP 系统架构设计方案...
  7. Python3.5安装与ChatterBot聊天机器人使用
  8. CentOS6.5上增加中文字体库,确保前端WEB可以正常显示
  9. 解决小键盘灯不亮的方法
  10. 中国地震数据集-包含经纬度及深度(2000-2020年)
  11. 什么是DNS的正向解析与反向解析?代码实现?
  12. opencv与openmv?
  13. 正确写出doublecheck的单例模式
  14. 小黄衫获得感想及经验总结
  15. MATLAB 人机对弈黑白棋
  16. 《ZigBee实战演练》
  17. SVN Clean up失败的解决方法
  18. Linux下 删除文件夹下的所有文件
  19. 100首经典好听的外文歌曲!
  20. 这些书你看过了多少?

热门文章

  1. 电信NB-IoT设备对接阿里云IoT平台实战——实践类
  2. MQTT协议与阿里云IoT物联网平台
  3. 【无标题】android 代码混淆 垃圾代码制造
  4. Sketch在线版免费使用,Windows也能用的Sketch!
  5. 用STM32+OV2560自己做一个USB摄像头
  6. java定时任务工具详解之Quartz
  7. EdrawMax v12新鲜出炉,重新设计字体库UI
  8. linux降级安装补丁,Adobe Shockwave Player降级安装漏洞
  9. 软件开发需要测试员吗?
  10. Numpy 函数 (一) squeeze(), unsquezze()