链接:No5、 用两个栈来实现一个队列 | 阿秀的学习笔记
第五题跳过。栈和队列等着代码随想录二刷补上。
JZ11 旋转数组的最小数字
链接:旋转数组的最小数字_牛客题霸_牛客网
代码:
这个二分法是左闭右开的,就真的不好理解。
class Solution { public: int minNumberInRotateArray(vector<int> nums) { int n=nums.size(); int left=0,right=n-1; while(left<right) { int mid=left+(right-left)/2; if(nums[mid]<nums[right])//右半截有序,且是升序 { right=mid; } else if(nums[mid]>nums[right])//在左半截有序,是升序 { left=mid+1; } else if(nums[mid]==nums[right]){ right--; } } return nums[right]; } };
leecode上做过一道类似的题,也是用的二分:
33.搜索旋转排序数组
链接:力扣
代码:
class Solution { public: int search(vector<int>& nums, int target) { int n=nums.size(); int left=0,right=n-1; while(left<=right) { int mid=left+(right-left)/2; if(nums[mid]==target) { return mid; } else if(nums[left]<=nums[mid])//左半截有序,这里有一个=号!!!! { if(nums[left]<=target && target<nums[mid]) { right=mid-1; } else { left=mid+1; } } else//右半截有序 { if(nums[right]>=target && target>nums[mid]) { left=mid+1; } else { right=mid-1; } } } return -1; } };
JZ69 跳台阶
链接: 跳台阶_牛客题霸_牛客网
class Solution { public: int jumpFloor(int number) { int a=1;//index=0; int b=1;//index=1 int c=0,index=1; //滚动向前 if(number==0 || number==1) { return 1; } while(index<number) { c=a+b; a=b; b=c; index++; } return c; } };
JZ71 跳台阶扩展问题
链接:跳台阶扩展问题_牛客题霸_牛客网
class Solution { public: int jumpFloorII(int number) { int a=1; for(int i=2;i<=number;i++) { a=2*a; } return a; } };
JZ9 用两个栈实现队列
链接:用两个栈实现队列_牛客题霸_牛客网
非正确思路:每次pop都要把stack2中的所有元素装回stack1
class Solution { public: void push(int node) {//一个栈只是存储,另一个栈在要pop的时候暂存除了要pop以外的的元素外所有元素,然后pop完再把所有值存回去 stack1.push(node); } int pop() { int value=-1; while(stack1.size()>1) { stack2.push(stack1.top()); stack1.pop(); } value=stack1.top(); stack1.pop(); while(!stack2.empty()) { stack1.push(stack2.top()); stack2.pop(); } return value; } private: stack<int> stack1; stack<int> stack2; };
正确思路,每次pop只是pop出stack2的栈顶元素,当stack2为空时,才一次性倒入所有stack1的元素。
class Solution { public: void push(int node) { stack1.push(node); } int pop() { int value=-1; if(stack2.empty()) { while(!stack1.empty()) { stack2.push(stack1.top()); stack1.pop(); } } if(!stack2.empty()) { value=stack2.top(); stack2.pop(); } return value; } private: stack<int> stack1; stack<int> stack2; };
No10、矩阵覆盖
链接:矩形覆盖_牛客题霸_牛客网
思路:
代码:
public class Solution { /*找规律: n=0,f[0]=0; n=1,f[1]=1; n=2,f[2]=2; n=3 f[3]=3; n=4,f[4]=5; f[n]=f[n-1]+f[n-2]; */ public int rectCover(int target) { if(target<2) { return target; } int f1=1; int f2=2; for(int i=3;i<=target;i++) { int temp=f1; f1=f2; f2=temp+f2; } return f2; } }
No11、二进制中1的个数
链接:二进制中1的个数_牛客题霸_牛客网
思路:
n&(n-1)把n最低位的1变0
class Solution { public: int NumberOf1(int n) { int cnt=0; while(n) { n=n&(n-1); cnt++; } return cnt; } };
JZ16 数值的整数次方
链接:数值的整数次方_牛客题霸_牛客网
leecode:力扣
这道题用到了快速幂。可以复习一下.
(1)快速幂+递归
class Solution { public: double myPow(double x, int n) { if(n==0) { return 1.0; } else if(n>0) { return QuickMul(x,n); } else { long long N=n;//特别注意,防止越界 return 1.0/QuickMul(x,(-1)*N); } } double QuickMul(double x,long long N) { if(N==0) { return 1.0; } else { double y=QuickMul(x,N/2); if(N%2==0) { return y*y; } else { return y*y*x; } } } };
(2)题解:力扣
class Solution { //快速幂+迭代非递归+位运算 public: double myPow(double x, int n) { long long N=n; if(n==0) { return 1; } else if(n<0) { return 1.0/quickMul(x,(-1)*N); } else { return quickMul(x,N); } } double quickMul(double x,long long N) { double res=1.0; while(N>0) { if(N&1==1) { res*=x; } x=x*x; N=N>>1; } return res; } };
调整数组顺序使奇数位于偶数前面
链接:调整数组顺序使奇数位于偶数前面_牛客题霸_牛客网
力扣
类似快排,这里有个很好的题解:力扣d
链表中倒数第k个结点
链接:链表中倒数第k个结点_牛客题霸_牛客网
第一种:快慢指针
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { //先后指针 ListNode *slow=pListHead,*fast=slow; while(k && fast!=nullptr) { k--; fast=fast->next; } if(fast==nullptr && k>0) { return nullptr; } else { while(fast!=nullptr) { slow=slow->next; fast=fast->next; } return slow; } } };
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { ListNode *p=pListHead; int len=0; while(p!=nullptr) { len++; p=p->next; } p=pListHead; if(len<k) { return nullptr; } else { cout<<len<<" "<<k<<endl; int t=len-k; while(t) { p=p->next; t--; } return p; } } };
No15、反转链表
链接:反转链表_牛客题霸_牛客网
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* ReverseList(ListNode* pHead) { if(pHead==nullptr || pHead->next==nullptr) { return pHead; } ListNode *slow=nullptr,*fast=pHead; while(fast!=nullptr) { ListNode *temp=fast; fast=fast->next; temp->next=slow; slow=temp; } return slow; } };
JZ25 合并两个排序的链表
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* Merge(ListNode* pHead1, ListNode* pHead2) { ListNode *L=new ListNode(-1); ListNode *p1=pHead1,*p2=pHead2,*r=L; while(p1!=nullptr && p2!=nullptr) { if(p1->val<p2->val) { r->next=p1; p1=p1->next; } else { r->next=p2; p2=p2->next; } r=r->next; } if(p1!=nullptr) { r->next=p1; } else { r->next=p2; } return L->next; } };
JZ26 树的子结构 ---------------写错
链接:树的子结构_牛客题霸_牛客网
/** * 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(B==NULL|| A == NULL)//约定空树不是任意一个树的子结构 return false; return is_thesame(A,B)||isSubStructure(A->left,B)|| isSubStructure(A->right,B); } bool is_thesame(TreeNode* A, TreeNode* B)//A的某段子树必须和B结构一样,所以用&& { if(B==NULL)//说明B到了底,遍历完了,此时可以说明前面遍历的节点都相同 { return true; } else if(A==NULL||A->val!=B->val)//B还没遍历完,A先遍历完了,说明不相等 { return false; } else { return is_thesame(A->left, B->left)&& is_thesame(A->right, B->right); } } };
No18、二叉树的镜像
链接:二叉树的镜像_牛客题霸_牛客网
力扣
/** * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * }; */ class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param pRoot TreeNode类 * @return TreeNode类 */ TreeNode* Mirror(TreeNode* pRoot) { //后序遍历 // write code here if(pRoot!=nullptr) { TreeNode *left=Mirror(pRoot->left) ; TreeNode *right=Mirror(pRoot->right) ; pRoot->left=right; pRoot->right=left; return pRoot; } return nullptr; } };
No19、顺时针打印矩阵
链接:顺时针打印矩阵_牛客题霸_牛客网
class Solution { public: vector<int>v; vector<int> printMatrix(vector<vector<int> > matrix) { int n=matrix.size(); int m=matrix[0].size(); // cout<<n<<endl; if(n==0) { return v; } int x1=0,y1=0,x2=n-1,y2=m-1; while(x1<x2 && y1<y2) { yiquan(x1,y1,x2,y2,matrix); x1++; y1++; x2--; y2--; } // cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl; if(x1==x2 && y1==y2)//剩下一个数 { v.push_back(matrix[x1][y1]); } else if(x1==x2)//剩下一行 { for(int j=y1;j<=y2;j++) { v.push_back(matrix[x1][j]); } } else if(y1==y2) {//剩下一列 for(int i=x1;i<=x2;i++) { v.push_back(matrix[i][y1]); } } return v; } void yiquan(int x1,int y1,int x2,int y2,vector<vector<int>> &matrix) { //左上角(x1,y1)右上角(x1,y2) 左下角(x2,y1) 右下角(x2,y2) // cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl; int i=x1; int j=y1; for(;j<y2;j++) { //cout<<matrix[i][j]<<" "; v.push_back(matrix[i][j]); } for(;i<x2;i++) { v.push_back(matrix[i][j]); } for(;j>y1;j--) { v.push_back(matrix[i][j]); } for(;i>x1;i--) { v.push_back(matrix[i][j]); } } };
这种更快,但是我没写过。
vector<int> printMatrix(vector<vector<int> > matrix) { if (matrix.size() == 0 || matrix[0].size() == 0) return vector<int>(); int left = 0, right = matrix[0].size() - 1, top = 0, bottom = matrix.size() - 1; vector<int> result; while (left <= right && top <= bottom) { for (int i = left; i <= right; ++i) { //cout << matrix[top][i] << " "; result.push_back(matrix[top][i]); } if (++top > bottom) break; for (int i = top; i <= bottom; ++i) { //cout << matrix[i][right] << " "; result.push_back(matrix[i][right]); } if (--right < left) break; for (int i = right ; i >= left; --i) { //cout << matrix[bottom][i] << " "; result.push_back(matrix[bottom][i]); } if (--bottom < top) break; for (int i = bottom; i >= top; --i) { //cout << matrix[i][left] << " "; result.push_back(matrix[i][left]); } if (++left > right) break; } return result; }
JZ30 包含min函数的栈 ----------不会做但是简单
链接:包含min函数的栈_牛客题霸_牛客网
class Solution { //单调栈?类似,有一个主栈记录所有正常值,一个辅助栈记录当前栈的最小值,每次都同时push和同时pop public: //int minn=INT_MIN; stack<int>A;//主栈 stack<int>B;//辅助栈 void push(int value) { A.push(value); if(B.empty()) { B.push(value); } else { if(value<B.top()) { B.push(value); } else { B.push(B.top());//重点,保持AB栈的元素个数一致,B可以重复push进最小值 } } } void pop() { A.pop(); B.pop(); } int top() { return A.top(); } int min() { return B.top(); } };
JZ31 栈的压入、弹出序列-----------自己做对
链接:栈的压入、弹出序列_牛客题霸_牛客网
自己做的:
class Solution { public: bool IsPopOrder(vector<int> pushV,vector<int> popV) { //给出的条件是 pushV 的所有数字均不相同 stack<int>st; int i=0,j=0; int n=pushV.size(); while(j<n) { while(i<n && pushV[i]!=popV[j]) { st.push(pushV[i]); i++; } st.push(pushV[i]);//把相等的元素push进栈 i++; while(!st.empty() && st.top()==popV[j]) { st.pop(); j++; } } if(!st.empty()) { return false; } return true; } };
JZ32 从上往下打印二叉树
链接:从上往下打印二叉树_牛客题霸_牛客网
层次遍历:
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { //层次遍历 public: vector<int> PrintFromTopToBottom(TreeNode* root) { queue<TreeNode*>q; vector<int>v; if(root==nullptr) { return v; } q.push(root); while(!q.empty()) { int len=q.size(); for(int i=0;i<len;i++) { TreeNode *temp=q.front(); q.pop(); v.push_back(temp->val); if(temp->left!=nullptr) { q.push(temp->left); } if(temp->right!=nullptr) { q.push(temp->right); } } } return v; } };
JZ33 二叉搜索树的后序遍历序列 --------中等
链接:二叉搜索树的后序遍历序列_牛客题霸_牛客网
力扣
显然没见过,显然没思路
最后自己写的:
class Solution { public: bool verifyPostorder(vector<int>& postorder) { int n=postorder.size(); return helper(postorder,0,n-1); } bool helper(vector<int>& postorder,int left,int right) { //如果left==right,就一个节点不需要判断了,如果left>right说明没有节点, //也不用再看了,否则就要继续往下判断 if(left>=right)//重点,这里一开始写错了 { return true; } int mid=left; int root=postorder[right];//最后一个元素是root while(postorder[mid]<root) { mid++; } int temp=mid; while(postorder[temp]>root) { temp++; } // cout<<left<<" "<<mid<<" "<<temp<<" "<<right<<endl; if(temp<right)//代表本次递归是可以的 { return false; } else { return helper(postorder,left,mid-1)&& helper(postorder,mid,right-1); } } };
这个题解写的非常好!
力扣
No24、二叉树中和为某一值的路径
链接:二叉树中和为某一值的路径(二)_牛客题霸_牛客网
花了些时间,用的是暴力回溯,也没加剪枝。基本正确吧
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ /* 注:该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点 */ class Solution { public: vector<vector<int>> v; vector<vector<int>> FindPath(TreeNode* root,int target) { vector<int>res; helper(root,0,target,res); return v; } void helper(TreeNode *root,int sum, int target,vector<int> &res)//回溯法+剪枝 { if(root!=nullptr) { res.push_back(root->val); if(root->left==nullptr && root->right==nullptr)//叶子节点 { sum+=root->val; //cout<<root->val<<" "<<sum<<endl; if(sum==target) { v.push_back(res); } sum-=root->val; } else {//非叶子节点 helper(root->left,sum+root->val,target,res); helper(root->right,sum+root->val,target,res); } res.pop_back(); } } };
JZ35 复杂链表的复制
链接:复杂链表的复制_牛客题霸_牛客网
这道题的重点是用一个map建立从源节点到复制节点的映射关系。今天只是看了思路,没有再做一遍。
/* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomListNode(int x) : label(x), next(NULL), random(NULL) { } }; */ class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { RandomListNode *copy_L=new RandomListNode(-1);//复制链表的头节点 RandomListNode *p1=pHead,*p2=copy_L; unordered_map<RandomListNode*,RandomListNode*>umap; while(p1) { // cout<<p1->label<<endl; RandomListNode *temp=new RandomListNode(p1->label); p2->next=temp; p2=temp; umap[p1]=p2;//记录从原链表节点到新复制节点链表之间的映射关系 p1=p1->next; } //重新更新深拷贝链表的random域 p2=copy_L->next; p1=pHead; while(p2 && p1) { //cout<<p2->label<<endl; p2->random=umap[p1->random]; p2=p2->next; p1=p1->next; } return copy_L->next; } };
No26、二叉搜索树与双向链表 ----------不会做
链接:二叉搜索树与双向链表_牛客题霸_牛客网
力扣-------leecode上这道题没做,和牛客网上略有差别
不会写,看了答案还有作图
答案参考:力扣
这个动图很清晰。
最后中序遍历完的状态是:
class Solution { Node head, pre; public Node treeToDoublyList(Node root) { if(root==null) return null; dfs(root); pre.right = head; head.left =pre;//进行头节点和尾节点的相互指向,这两句的顺序也是可以颠倒的 return head; } public void dfs(Node cur){ if(cur==null) return; dfs(cur.left); //pre用于记录双向链表中位于cur左侧的节点,即上一次迭代中的cur,当pre==null时,cur左侧没有节点,即此时cur为双向链表中的头节点 if(pre==null) head = cur; //反之,pre!=null时,cur左侧存在节点pre,需要进行pre.right=cur的操作。 else pre.right = cur; cur.left = pre;//pre是否为null对这句没有影响,且这句放在上面两句if else之前也是可以的。 pre = cur;//pre指向当前的cur dfs(cur.right);//全部迭代完成后,pre指向双向链表中的尾节点 } }
自己敲:
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ /* 这道题好像做过 要求不能创建任何新的结点,只能调整树中结点指针的指向 左指针需要指向前驱,树中节点的右指针需要指向后继 */ TreeNode *pre=nullptr, *phead=nullptr; class Solution { public: TreeNode* Convert(TreeNode* root) { if(root==nullptr) { return nullptr; } Inorder(root); /* pre->right = phead; phead->left =pre;//进行头节点和尾节点的相互指向,这两句的顺序也是可以颠倒的 */ return phead; } //中序遍历 void Inorder(TreeNode *root) { if(root!=nullptr) { Inorder(root->left); //先中序遍历 if(pre==nullptr)//如果pre==nullptr,基本可以确定为头节点 { phead=root;//等于的是root,当前一定是头节点 } else { pre->right=root;//这里要想着那张图 } root->left=pre; pre=root;//要往前挪 Inorder(root->right); } } };
JZ38 字符串的排列-------------------基本是对照着写的,还有模糊的地方
链接:字符串的排列_牛客题霸_牛客网
这道题建议复习一下我前面写的排列问题:
代码随想录|day29|回溯算法part05* 491.递增子序列* 46.全排列* 47.全排列 II_isabelightL的博客-CSDN博客
class Solution { public: //排列问题,而且可能出现重复字符。这个就是回溯法中的组合和排列问题 vector<string>v; string s; vector<string> Permutation(string str) { int n=str.size(); vector<bool>used; used.resize(n,false); sort(str.begin(),str.end()); backtracing(str,used); return v; } void backtracing(string &str,vector<bool> &used) { if(s.size()==str.size()) { v.push_back(s); } else { for(int j=0;j<str.size();j++) { if(j>0 && str[j]==str[j-1] && used[j-1]==false) { continue; } if(used[j]==false) { used[j]=true; s.push_back(str[j]); backtracing(str,used); s.pop_back(); used[j]=false;//回溯 } } } } };
JZ39 数组中出现次数超过一半的数字----简单题
链接:数组中出现次数超过一半的数字_牛客题霸_牛客网
力扣
题解:力扣
摩尔投票法,
class Solution { public: /* 注意空间复杂度和时间复杂度 */ int MoreThanHalfNum_Solution(vector<int> nums) { int n=nums.size(); int candicate=nums[0]; int cnt=1; for(int i=1;i<n;i++) { //如果cnt==0,重新更新候选人candicate if(cnt==0) { candicate=nums[i]; } if(nums[i]==candicate) { cnt++; } else { cnt--; } } return candicate; } };
JZ40 最小的K个数
链接:最小的K个数_牛客题霸_牛客网
最大最小堆
自己做的:
class Solution { public: /* 求最小的k个数,则每次pop出最大数,故为最大堆,优先队列 priority_queue<int,vector<int>,greater>qu; */ vector<int> GetLeastNumbers_Solution(vector<int> nums, int k) { vector<int>v; priority_queue<int,vector<int>>qu; int n=nums.size(); for(int i=0;i<n;i++) { qu.push(nums[i]); if(qu.size()>k) { qu.pop(); } } while(!qu.empty()) { int temp=qu.top(); v.push_back(temp); qu.pop(); } return v; } };
JZ42 连续子数组的最大和
链接:连续子数组的最大和_牛客题霸_牛客网
class Solution { public: //记得是动态规划 int FindGreatestSumOfSubArray(vector<int> nums) { int n=nums.size(); vector<int>dp(n,0); dp[0]=nums[0]; int maxx=nums[0]; for(int i=1;i<n;i++) { dp[i]=max(dp[i-1]+nums[i],nums[i]); maxx=max(maxx,dp[i]); } return maxx; } };
JZ43 整数中1出现的次数(从1到n整数中1出现的次数)
链接:整数中1出现的次数(从1到n整数中1出现的次数)_牛客题霸_牛客网
力扣
暴力法在leecode上超时。
题解列到这里,真不好理解。最后不会做
力扣
JZ45 把数组排成最小的数 ------不会做
链接:把数组排成最小的数_牛客题霸_牛客网
力扣
c++ lambda 表达式:C++ lambda表达式与函数对象 - 简书
sort里的自定义函数C++中的sort自定义排序函数_cpp sort自定义_Daniel_lmz的博客-CSDN博客
普通的sort自定义排序,注意cmp前加static
class Solution { public: static bool cmp(string &s1,string &s2) { return s1+s2<s2+s1; } string PrintMinNumber(vector<int> numbers) { vector<string>v; for(auto num:numbers) { v.push_back(to_string(num)); } sort(v.begin(),v.end(),cmp); string ans=""; for(auto str:v) { ans+=str; } return ans; } };
sort自定义函数用匿名函数写:
class Solution { public: string PrintMinNumber(vector<int> numbers) { //先转换成字符串排序,用到sort自定义函数,试写lambda vector<string> v; string ans=""; for(auto num :numbers) { v.push_back(to_string(num)); } sort(v.begin(),v.end(),[](string &s1,string &s2){ return s1+s2<s2+s1;}); for(auto str:v) { ans+=str; } return ans; } };
JZ49 丑数 ------不会做
链接:丑数_牛客题霸_牛客网
最清晰易懂的题解:力扣
照着题解写一遍。
class Solution { //看了题解,是动态规划,且合并三个有序序列 public: int GetUglyNumber_Solution(int index) { vector<int>dp(index+1,0); dp[0]=1; int p2=0,p3=0,p5=0; for(int i=1;i<index;i++) { dp[i]=min(dp[p5]*5,min(dp[p2]*2,dp[p3]*3)); if(dp[i]==dp[p2]*2) { p2++; } if(dp[i]==dp[p3]*3) { p3++; } if(dp[i]==dp[p5]*5) { p5++; } cout<<dp[i]<<endl; } return dp[index-1]; } };
JZ50 第一个只出现一次的字符
链接:第一个只出现一次的字符_牛客题霸_牛客网
class Solution { //考虑空间复杂度和时间复杂度 public: int FirstNotRepeatingChar(string str) { unordered_map<char,int>umap; for(auto ch:str) { umap[ch]++; } for(int i=0;i<str.size();i++) { if(umap[str[i]]==1) { return i; } } return -1; } };
JZ51 数组中的逆序对-------困难,且归并排序
链接:力扣
链接:数组中的逆序对_牛客题霸_牛客网
自己照着原来的代码进行了二敲
最重要的思路是在归并排序的归并过程中统计逆序对
class Solution { //归并排序 public: vector<int>temp; int cnt=0;//计算逆序的次数 int reversePairs(vector<int>& nums) { int n=nums.size(); temp.resize(n,0); Merge_Sort(nums,0,n-1); for(auto num:nums) { cout<<num<<" "; } return cnt; } void Merge_Sort(vector<int> &nums,int low,int high) { if(low<high) { int mid=low+(high-low)/2; Merge_Sort(nums,low,mid); Merge_Sort(nums,mid+1,high); Merge(nums,low,mid,high); } } void Merge(vector<int> &nums,int low,int mid,int high) { for(int j=low;j<=high;j++) { temp[j]=nums[j]; } int i=low,j=mid+1,k=low; while(i<=mid && j<=high) { if(temp[i]<=temp[j]) { nums[k++]=temp[i++]; } else { nums[k++]=temp[j++]; cnt+= mid-i+1; } } while(i<=mid) { nums[k++]=temp[i++]; } while(j<=high) { nums[k++]=temp[j++]; } } };
带注释的注解答案(JAVA):
class Solution { //利用归并排序解答,在合并的时候,当左边的大于右边,就计算逆序数。 //计算公式; mid-left+1 //定义一个全局的计数器变量 int count = 0; public int reversePairs(int[] nums) { this.count = 0; mergeSort(nums, 0, nums.length-1); return count; } public void mergeSort(int[] nums,int left,int right){ //当只有一个节点的时候,直接返回,退出递归 if(left >= right){ return; } int mid = (left+right)/2; //左拆分 mergeSort(nums,left,mid); //右拆分 mergeSort(nums,mid+1,right); //合并 merge(nums,left,mid,right); } public void merge(int[] nums,int left,int mid,int right){ //定义一个临时数组 int[] temp = new int[right-left+1]; //定义一个指针,指向第一个数组的第一个元素 int i = left; //定义一个指针,指向第二个数组的第一个元素 int j = mid+1; //定义一个指针,指向临时数组的第一个元素 int t = 0; //当两个数组都有元素的时候,遍历比较每个元素大小 while(i <= mid && j <= right){ //比较两个数组的元素,取较小的元素加入到,临时数组中 //并将两个指针指向下一个元素 if(nums[i] <= nums[j]){ temp[t++] = nums[i++]; }else{ //当左边数组的大与右边数组的元素时,就对当前元素以及后面的元素的个数进行统计, //此时这个数就是,逆序数 //定义一个计数器,记下每次合并中存在的逆序数。 count += mid-i+1; temp[t++] = nums[j++]; } } //当左边的数组没有遍历完成后,直接将剩余元素加入到临时数组中 while(i <= mid){ temp[t++] = nums[i++]; } //当右边的数组没有遍历完成后,直接将剩余元素加入到临时数组中 while(j <= right){ temp[t++] =nums[j++]; } //将新数组中的元素,覆盖nums旧数组中的元素。 //此时数组的元素已经是有序的 for(int k =0; k< temp.length;k++){ nums[left+k] = temp[k]; } } }
fdgsf
fg
JZ52 两个链表的第一个公共结点
链接:两个链表的第一个公共结点_牛客题霸_牛客网
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { //这个也做了很多遍了 public: ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { ListNode *p1=pHead1,*p2=pHead2; int len1=0,len2=0; while(p1!=nullptr) { p1=p1->next; len1++; } while(p2!=nullptr) { p2=p2->next; len2++; } int maxx_len=max(len1,len2); int t=abs(len1-len2); p1=pHead1; p2=pHead2; if(maxx_len==len1) { while(t) { p1=p1->next; t--; } //cout<<p1->val<<endl; } else { while(t) { p2=p2->next; t--; } //cout<<p2->val<<endl; } while(p1!=p2) { p1=p1->next; p2=p2->next; } return p1; } };
JZ53 数字在升序数组中出现的次数
链接:数字在升序数组中出现的次数_牛客题霸_牛客网
可寻找左右两侧边界,参考【labuladong的算法小抄】二分查找 - 简书
class Solution { public: int find_leftbound(vector<int>&nums,int k,int left,int right) { int n=nums.size(); while(left<=right) { int mid=left+(right-left)/2; if(nums[mid]==k) { right=mid-1; } else if(nums[mid]<k) { left=mid+1; } else { right=mid-1;//找左边界时收缩右侧边界 } } if(left>=n || nums[left]!=k) { return -1; } return left; } int find_rightbound(vector<int>&nums,int k,int left,int right) { int n=nums.size(); while(left<=right) { int mid=left+(right-left)/2; if(nums[mid]==k) { left=mid+1; } else if(nums[mid]<k) { left=mid+1; } else { right=mid-1;//找右边界时收缩左侧边界 } } if(right<0 || nums[right]!=k) { return -1; } return right; } //主函数 int GetNumberOfK(vector<int> nums ,int k) { //二分法 int n=nums.size(); int right=n-1; int left=0; if(n==0) { return 0; } if(k<nums[0]||k>nums[n-1]) { return 0; } //寻找左侧边界 int leftbound=find_leftbound(nums,k,left,right); int rightbound=find_rightbound(nums,k,left,right); // cout<<leftbound<<" "<<rightbound<<endl; if(leftbound==-1 || rightbound==-1)//左右边界都找不到,则不存在 { return 0; } return rightbound-leftbound+1; } };
JZ55 二叉树的深度----简单
链接:二叉树的深度_牛客题霸_牛客网
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: int TreeDepth(TreeNode* pRoot) { if(pRoot==nullptr) { return 0; } return dfs(pRoot); } int dfs(TreeNode *root) { if(root==nullptr) { return 0; } int left=dfs(root->left); int right=dfs(root->right); return max(left,right)+1; } };
JZ79 判断是不是平衡二叉树 -----简单
链接:判断是不是平衡二叉树_牛客题霸_牛客网
class Solution { //还有一道题是查看是不是平衡二叉搜索树 //借用左右子树差,如果叉超过1,直接返回false public: bool flag=true; bool IsBalanced_Solution(TreeNode* pRoot) { int depth=dfs(pRoot); return flag; } int dfs(TreeNode *root) { if(root==nullptr) { return 0; } int left=dfs(root->left); int right=dfs(root->right); if(abs(right-left)>1) { flag=false; } return max(left,right)+1; } };
No40、数组中只出现一次的数字 -------位运算,不会
链接:数组中只出现一次的数字_牛客题霸_牛客网
力扣
代码:
class Solution { public: vector<int> singleNumbers(vector<int>& nums) { //位运算,异或操作 /* 先对所有数字进行一次异或,得到两个出现一次的数字的异或值。 在异或结果中找到任意为 1 的位。 根据这一位对所有的数字进行分组。 在每个组内进行异或操作,得到两个数字。 */ int res=0; for(int i=0;i<nums.size();i++) { res^=nums[i]; } //res是两个缺失数的异或值,这两个数互不相等,因此必定存在某一位一个0一个1,即异或为1,根据这一位可以将两个数分到不同组 //2、在异或结果中找到任意为 1 的位。 unsigned int v=1; while((res&v)==0) { v<<=1; } cout<<v<<endl; int a=0,b=0; for(auto num:nums) { cout<<(num&v)<<endl; } for(auto num:nums) { if(num&v)//那一位等于1 { a^=num; } else//那一位等于0的 { b^=num; } } return vector<int>{a,b}; } };
二刷:
class Solution { public: void FindNumsAppearOnce(vector<int> nums,int* num1,int *num2) { //这个函数的意思是把找到的两个不同的数放到nums1和nums2 int n=nums.size(); int res=0;//res是两个不同的数异或的结果 for(auto num:nums) { res=res^num; } //找到res位为1的最低位,根据为1的这一位将两个数分开,比如res==1001000,则想求的v就是0001000 unsigned int v=1; while((res&v)==0) { v<<=1;//如果==0,就把v左移 } int a=0,b=0; for(auto num :nums) { if(num&v)//只要不是0 { a=a^num; } else { b=b^num; } } *num1=a; *num2=b; } };
JZ74 和为S的连续正数序列
链接:力扣
链接:和为S的连续正数序列_牛客题霸_牛客网
这道题直接看的牛客网的解法,感觉很清晰易懂。
class Solution { //牛客网同样的题 https://www.nowcoder.com/practice/c451a3fd84b64cb19485dad758a55ebe?tpId=13&&tqId=11194&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking public: vector<vector<int>> findContinuousSequence(int target) { vector<vector<int>>v; int low=1,high=2; while(low<high && high<target) { long long sum=(low+high)*(high-low+1)/2; if(sum==target) { vector<int>mv; for(int i=low;i<=high;i++) { mv.push_back(i); } v.push_back(mv); //找到满足条件的序列后,整个窗口需要左移 low++; } else if(sum<target) { high++; } else { low++; } } return v; } };
JZ57 和为S的两个数字
链接:和为S的两个数字_牛客题霸_牛客网
链接:力扣
自己用的哈希表,但是这道题的本意是用双指针
vector<int> FindNumbersWithSum(vector<int> array,int sum) { vector<int> result; if (array.size() == 0) return result; int low = 0, high = array.size() - 1; while (low < high) { if (array[low] + array[high] == sum) { result.push_back(array[low]); result.push_back(array[high]); return result; } else if (array[low] + array[high] < sum) low++; else { high--; } } return result; }
JZ58 左旋转字符串
链接:力扣
链接:左旋转字符串_牛客题霸_牛客网
class Solution { //面对简单题我重拳出击,偶霍霍 //一般旋转用到%n public: string reverseLeftWords(string s, int n) { int len=s.size(); string ns; ns.resize(len); //cout<<ns.size()<<endl; for(int i=0;i<len;i++) { ns[(i-n+len)%len]=s[i]; } return ns; } };
剑指 Offer 58 - I. 翻转单词顺序--------虽然是简单题但是有点不会
两道题在leecode和牛客网上不太一样,leecode上中间也有空格,必须去除;leecode上更加严格
链接:力扣
链接:翻转单词序列_牛客题霸_牛客网
进阶版,但是只看了代码:
class Solution { public: string reverseWords(string s) { // 反转整个字符串 reverse(s.begin(), s.end()); int n = s.size(); int idx = 0; for (int start = 0; start < n; ++start) { if (s[start] != ' ') { // 填一个空白字符然后将idx移动到下一个单词的开头位置 if (idx != 0) s[idx++] = ' '; // 循环遍历至单词的末尾 int end = start; while (end < n && s[end] != ' ') s[idx++] = s[end++]; // 反转整个单词 reverse(s.begin() + idx - (end - start), s.begin() + idx); // 更新start,去找下一个单词 start = end; } } s.erase(s.begin() + idx, s.end()); return s; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/fan-zhuan-dan-ci-shun-xu-lcof/solutions/1398807/fan-zhuan-dan-ci-shun-xu-by-leetcode-sol-vnwj/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
自己写的,更好理解。用到了栈和原字符串:
class Solution { public: string reverseWords(string str) { int n = str.length(); stack<string> st; //去除前后空格 int left=0,right=n-1; while(left<=right && str[left]==' ') { left++; } while(left<=right && str[right]==' ') { right--; } //遍历字符串,找到单词并入栈 for(int i = left; i <= right; i++){ int j = i; //以空格为界,分割单词 if(str[j]!=' ') { while(j <=right && str[j] != ' ') { j++; } //单词进栈 st.push(str.substr(i, j - i)); i=j; } } //清空原先的字符串 str=""; //栈遵循先进后出,单词顺序是反的 while(!st.empty()){ str += st.top(); cout<<st.top()<<endl; st.pop(); if(!st.empty()) str += " "; } return str; } };
JZ61 扑克牌顺子
链接:扑克牌顺子_牛客题霸_牛客网
链接:力扣
我已经全部都忘了,还要看以前的解法才能回忆起来。
主要思路是排序,计算0的个数,计算相邻两张牌的差值,看0的个数能不能弥补这些差值,就像填坑一样。
class Solution { public: bool IsContinuous( vector<int> nums ) { sort(nums.begin(),nums.end()); int n=nums.size(); int i=0; int zero_cnt=0; while(i<n && nums[i]==0) { i++; zero_cnt++; } //从第一个不为0的数开始计算 int sum=0; for(;i+1<n;i++) { if(nums[i+1]==nums[i]) { return false; } else { sum+=nums[i+1]-nums[i]-1; } } cout<<sum<<" "<<zero_cnt<<endl; if(sum<=zero_cnt) { return true; } return false; } };
孩子们的游戏
链接:孩子们的游戏(圆圈中最后剩下的数)_牛客题霸_牛客网
class Solution { //约瑟夫环 public: int LastRemaining_Solution(int n, int m) { if(n<=0) { return -1; } int f=0; // 最后一轮剩下2个人,所以从2开始反推 //第一轮有n个人,所以<n+1 for(int i=2;i<n+1;i++) { f=(m+f)%i;//. f(n,m) = (f(n-1,m)+m) %n; } return f; } };
47题没有做,感觉又偏又怪
不用加减乘除做加法
链接:不用加减乘除做加法_牛客题霸_牛客网
把字符串转换成整数
链接:力扣
链接:牛客网 把字符串转换成整数_牛客题霸_牛客网
有很多要注意到的小细节,但是感觉做起来没多大意义,自己对照测试用例改了几次代码。
class Solution { public: int strToInt(string s) { long long sum=0; int i=0; int n=s.size(); if(n<=0)//1、空字符串,返回0 { return 0; } while(i<n && s[i]==' ')//2、去除尽可能多的空格 { i++; } //----处理第一个非空字符------ //首先判断i是否越界,因为有可能是一个很长的空字符串 if(i>=n) { return 0; } int flag=1;//判断是否为正数,正数为1,负数为-1 if(s[i]<='9'&& s[i]>='0')//第一位是数字 { //不做任何处理 } else if(s[i]=='+') { i++; } else if(s[i]=='-') { flag=-1; i++; } else//第一个字符不是一个有效整数字符 { return 0; } //由于可能只存在"-",再次检验i是否越界 if(i>=n) { return 0; } cout<<flag<<" "<<i<<endl; //cout<<INT_MAX<<" "<<INT_MIN<<endl; //开始算正整数部分 while(i<n && s[i]<='9'&& s[i]>='0') { int num=s[i]-'0'; sum=sum*10+num; if(flag*sum<INT_MIN) { return INT_MIN; } if(flag*sum>INT_MAX) { return INT_MAX; } i++; } sum=flag*sum; return (int)sum; } };
改了几次代码数组中重复的数字 ---------------太简单了没有做的价值
链接:数组中重复的数字_牛客题霸_牛客网
力扣
class Solution { public: int findRepeatNumber(vector<int>& nums) { unordered_set<int>us; for(auto num:nums) { if(us.find(num)!=us.end()) { return num; } us.insert(num); } return -1; } };
JZ66 构建乘积数组
构建乘积数组_牛客题霸_牛客网思路:
class Solution { public: vector<int> multiply(const vector<int>& A) { //分成左右数组 int n=A.size(); vector<int>left(n,1);//left[i]=a[0]*a2*...a[i-1] vector<int>right(n,1);//right[i]=a[i+1]*...a[n-1] right[n-2]=a[n-1] // right[n-3]=a[n-1]*a[n-2] int sum=1; for(int i=1;i<n;i++) { sum=sum*A[i-1]; left[i]=sum; } sum=1; for(int i=n-2;i>=0;i--) { sum=sum*A[i+1]; right[i]=sum; } vector<int>B(n,0); for(int i=0;i<n;i++) { //cout<<left[i]<<" "<<right[i]<<endl; B[i]=left[i]*right[i]; } return B; } };
a
a
a
a
正则表达式匹配
这个 题解很好力扣
class Solution { public: bool isMatch(string s, string p) { // 在p为空后 只需要查看s是否为空即可 if(p.empty()) return s.empty(); //判断首个元素是否匹配 bool first_match = !s.empty() && (s[0] == p[0] || p[0] == '.'); //如果下个字符是'*' //*前字符重复0次||重复>=1次 if(p[1] == '*' && p.size() >= 2) return isMatch(s, p.substr(2)) || (first_match && isMatch(s.substr(1), p)); //一般情况 else return first_match && isMatch(s.substr(1), p.substr(1)); } };
递归做法没有看。
No53、表示数值的字符串 ----------没做
链接:力扣
JZ75 字符流中第一个不重复的字符
链接:字符流中第一个不重复的字符_牛客题霸_牛客网
class Solution { public: unordered_map<char,int>m; vector<int>v; //Insert one char from stringstream void Insert(char ch) { m[ch]++; v.push_back(ch); } //return the first appearence once char in current stringstream char FirstAppearingOnce() { for(auto ch :v) { if(m[ch]==1) { return ch; } } return '#'; } };
JZ23 链表中环的入口结点
链接:链表中环的入口结点_牛客题霸_牛客网
自己的写法,但是报错:
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */ class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { if(pHead==nullptr || pHead->next==nullptr|| pHead->next->next==nullptr) { return nullptr; } //由两个节点或者一个节点组成的环 if(pHead->next==pHead || pHead->next->next==pHead) { return pHead; } //三个及以上的节点 ListNode *slow=pHead; ListNode *fast=pHead; while(fast->next!=nullptr) { slow=slow->next; fast=fast->next->next; if(slow==fast)//有相遇节点 { slow=pHead; while(slow!=fast) { slow=slow->next; fast=fast->next; if(slow==fast) { return slow; } } } } return nullptr; } };
第二遍改为:
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */ class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { if(pHead==nullptr || pHead->next==nullptr|| pHead->next->next==nullptr) { return nullptr; } //由两个节点或者一个节点组成的环 if(pHead->next==pHead || pHead->next->next==pHead) { return pHead; } //三个及以上的节点 ListNode *slow=pHead; ListNode *fast=pHead; while(fast!=nullptr && fast->next!=nullptr) { slow=slow->next; fast=fast->next->next; if(slow==fast)//有相遇节点 { slow=pHead; while(slow!=fast) { slow=slow->next; fast=fast->next; } return slow; } } return nullptr; } };
No56、删除链表中的重复结点 ----------二刷也不会
链接:删除链表中重复的结点_牛客题霸_牛客网
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */ class Solution { public: ListNode* deleteDuplication(ListNode* pHead) { ListNode *L=new ListNode(-1); L->next=pHead; ListNode *pre=L,*slow=L->next; while(slow!=nullptr && slow->next!=nullptr) { if(slow->val==slow->next->val) { int temp=slow->val; while(slow!=nullptr && slow->val==temp) { slow=slow->next; } pre->next=slow; } else { pre=slow; slow=slow->next; } } return L->next; } };
No57、二叉树的下一个结点
链接:No57、二叉树的下一个结点 | 阿秀的学习笔记
题目比较奇怪,我自己的想法也比较巧妙。
/* struct TreeLinkNode { int val; struct TreeLinkNode *left; struct TreeLinkNode *right; struct TreeLinkNode *next; TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) { } }; */ class Solution { public: //无语了这个题,真心奇怪 TreeLinkNode *pre=nullptr; TreeLinkNode *findNode=nullptr; TreeLinkNode* GetNext(TreeLinkNode* pNode) { TreeLinkNode *root=pNode; //找到头节点 while(root->next!=nullptr) { root=root->next; } Inorder(root,pNode); return findNode; } void Inorder(TreeLinkNode * &root,TreeLinkNode * &pNode) { if(root!=nullptr) { Inorder(root->right,pNode); if(root==pNode) { findNode=pre; } pre=root; Inorder(root->left,pNode); } } };
JZ28 对称的二叉树
链接:对称的二叉树_牛客题霸_牛客网
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; */ class Solution { public: bool if_true=true; bool isSymmetrical(TreeNode* pRoot) { helper(pRoot,pRoot); return if_true; } void helper(TreeNode *pRoot1, TreeNode *pRoot2) { if(pRoot1==nullptr && pRoot2!=nullptr) { if_true=false; } else if(pRoot1!=nullptr && pRoot2==nullptr) { if_true=false; } else if(pRoot1!=nullptr && pRoot2!=nullptr) { if(pRoot1->val!=pRoot2->val) { if_true=false; } helper(pRoot1->left, pRoot2->right); helper(pRoot1->right, pRoot2->left); } } };
之字形打印二叉树
链接:按之字形顺序打印二叉树_牛客题霸_牛客网
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; */ class Solution { public: vector<vector<int> > Print(TreeNode* pRoot) { //很显然是层序遍历,然后每层的res再reverse queue<TreeNode*>q; vector<vector<int>>v; if(pRoot==nullptr) { return v; } q.push(pRoot); //cout<<pRoot->val<<endl; int index=0; while(!q.empty()) { int len =q.size(); vector<int>res; for(int i=0;i<len;i++) { TreeNode *temp=q.front(); res.push_back(temp->val); q.pop(); if(temp->left) { q.push(temp->left); } if(temp->right) { q.push(temp->right); } } if(index%2==1) { reverse(res.begin(),res.end()); } /*for(auto p:res) { cout<<p<<" "; } cout<<endl; */ v.push_back(res); index++; } return v; } };
JZ78 把二叉树打印成多行
链接:把二叉树打印成多行_牛客题霸_牛客网
最简单的层序遍历。
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; */ class Solution { public: vector<vector<int>>v; vector<vector<int> > Print(TreeNode* root) { queue<TreeNode*>q; if(root==nullptr) { return v; } q.push(root); while(!q.empty()) { int len=q.size(); vector<int>mv; for(int i=0;i<len;i++) { TreeNode *temp=q.front(); mv.push_back(temp->val); q.pop(); if(temp->left) { q.push(temp->left); } if(temp->right) { q.push(temp->right); } } v.push_back(mv); } return v; } };
No61、序列化二叉树-------------难度为困难,打算之后再看
链接:序列化二叉树_牛客题霸_牛客网
链接:力扣
同时还有一道序列化与反序列化二叉树
链接:力扣
二叉搜索树的第K个节点 -------简单,勿看
链接:力扣
/** * 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: //二叉搜索树中序遍历(反着)就是第k大的数 int cnt=1; int value=-1; int kthLargest(TreeNode* root, int k) { reverse_inorder(root,k); return value; } void reverse_inorder(TreeNode *root, int k) { if(root!=nullptr) { reverse_inorder(root->right,k); if(cnt==k) { value=root->val; } cnt++; reverse_inorder(root->left,k); } } };
JZ41 数据流中的中位数 ---------优先队列,值得再看
链接:数据流中的中位数_牛客题霸_牛客网
链接:力扣
题解:力扣
牛客网刷一遍:
#include <functional> class Solution { public: //7 A:4,5,6,7 B: 1,2,3 // 6 A:4,5,6 B:1,2,3 //创建两个堆,一个小顶堆A,储存较大的一半数,每次pop最小值; // 一个大顶堆B,储存较小的一半数,每次pop最大值; priority_queue<int,vector<int>,greater<int>>A; priority_queue<int,vector<int>>B;//默认大顶堆!! void Insert(int num) { if(A.size()==B.size())//已经装了偶数个数,现在要装奇数个数 { B.push(num); A.push(B.top()); B.pop(); } else { A.push(num); B.push(A.top()); A.pop(); } } double GetMedian() { double num1=static_cast<double>(A.top()); double num2=static_cast<double>(B.top()); if(A.size()==B.size()) { return (num1+num2)/2; } else { return num1; } } };
class MedianFinder { public: /** initialize your data structure here. */ //创建两个堆 //优先队列默认大根堆 priority_queue<int,vector<int>,greater<int>>A;//小根堆,每次pop出最小值,存储较大的一半,较大值里的最小的,当然是中位数的备选值 priority_queue<int,vector<int>>B;//大根堆,每次pop出最大值,存储较小的一半,最小一半的最大值,当然是中位数的备选值 //如果序列是奇数个,则比如有7个数,则A中保存 4,5,6,7;B中保存1,2,3 //如果序列是偶数个,则比如有8个数,则A中保存 5,6,7,8;B中保存1,2,3,4 MedianFinder() { } void addNum(int num) { if(A.size()==B.size())//原本是偶数个,现在添加一个要变成奇数个 { B.push(num); A.push(B.top()); B.pop(); } else//原本奇数个,现在要变成偶数个 { A.push(num); B.push(A.top()); A.pop(); } } double findMedian() { if(A.size()==B.size()) { double num1= static_cast<double>(A.top()); double num2=static_cast<double>(B.top()); return (num1+num2)/2; } else { return static_cast<double>(A.top()); } } }; /** * Your MedianFinder object will be instantiated and called as such: * MedianFinder* obj = new MedianFinder(); * obj->addNum(num); * double param_2 = obj->findMedian(); */
JZ59 滑动窗口的最大值 --------单调队列,值得二刷
链接:滑动窗口的最大值_牛客题霸_牛客网
代码随想录里 也有这道题。
代码随想录
这是当时写的题解:
class Solution { private: //创建单调队列的class class DandiaoQueue{ public: deque<int>d;//底层实现 void push(int x) { while(!d.empty()&&x>d.back()) { d.pop_back(); } d.push_back(x); } void pop(int left) { if(left==d.front()) { d.pop_front(); } } int maxx() { return d.front(); } }; public: /* 总的来说,结合https://programmercarl.com/0239.%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC.html 和https://labuladong.github.io/algo/di-yi-zhan-da78c/shou-ba-sh-daeca/dan-diao-d-32cd5/ 来理解 单调队列用到压扁的比喻让人印象深刻 单调队列、单调栈、滑动窗口、优先队列 区别 现在需要一种新的队列结构,既能够维护队列元素「先进先出」的时间顺序,又能够正确维护队列中所有元素的最值,这就是「单调队列」结构 队列没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。 那么这个维护元素单调递减的队列就叫做单调队列,即单调递减或单调递增的队列。C++中没有直接支持单调队列,需要我们自己来实现一个单调队列 不要以为实现的单调队列就是 对窗口里面的数进行排序,如果排序的话,那和优先级队列又有什么区别了呢。 */ vector<int> maxSlidingWindow(vector<int>& nums, int k) { DandiaoQueue myque; vector<int>res;//res中存储当前滑动窗口最大值 int n=nums.size(); //先把k个元素送进单调队列 int i=0; while(i<k) { myque.push(nums[i]); i++; } res.push_back(myque.maxx()); //接下来维护大小为k的滑动窗口,保证进一个新元素,走一个滑动窗口中的元素----这里卡住了,怎么接着往下写? for(i=k;i<n;i++) { myque.pop(nums[i-k]);//如果不是不做任何处理 myque.push(nums[i]); res.push_back(myque.maxx()); } return res; } };
现在相当于二刷:
class Myqueue{ public: deque<int>de; void push(int value)//处理单调队列尾部 { while(!de.empty()&& value > de.back()) { de.pop_back(); } de.push_back(value); } void pop(int value)//处理单调队列头部 { if(!de.empty() && de.front()==value) { de.pop_front(); } } int maxx() { return de.front(); } }; class Solution { //具体参照https://leetcode.cn/problems/sliding-window-maximum/submissions/412558078/ public: vector<int> maxInWindows(const vector<int>& num, unsigned int size) { vector<int>res; Myqueue q; int n=num.size(); //大于数组长度或窗口长度==0,返回空 if(size>n ||size==0) { return res; } int i=0; while(i<size) { q.push(num[i]); i++; } res.push_back(q.maxx()); for(i=size;i<n;i++) { q.pop(num[i-size]); q.push(num[i]); res.push_back(q.maxx()); } return res; } };
剑指 Offer 12. 矩阵中的路径
链接:矩阵中的路径_牛客题霸_牛客网
链接:力扣
经典回溯,但是写错了。
class Solution { public: bool flag=false; vector<int>xx={0,0,-1,1}; vector<int>yy={-1,1,0,0}; bool exist(vector<vector<char>>& board, string word) { int n=board.size(); int m=board[0].size(); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(board[i][j]==word[0]) { backtracing(board,i,j,word,0); } } } return flag; } void backtracing(vector<vector<char>>& board,int i,int j,string &word,int t) { if(t==word.size()-1) { flag=true; } int m=board.size(); int n=board[0].size(); char ch=board[i][j]; if(board[i][j]==word[t]) { board[i][j]='#'; for(int k=0;k<4;k++) { int new_i=i+xx[k]; int new_j=j+yy[k]; if(new_i>=0 && new_i<m && new_j>=0 && new_j<n && board[new_i][new_j]!='#') { backtracing(board,new_i,new_j,word,t+1); } } board[i][j]=ch; } } };
c重新修改,必须检查最后一个字符才行!
class Solution { public: bool flag=false; vector<int>xx={0,0,-1,1}; vector<int>yy={-1,1,0,0}; bool exist(vector<vector<char>>& board, string word) { int n=board.size(); int m=board[0].size(); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(board[i][j]==word[0]) { backtracing(board,i,j,word,0); } } } return flag; } void backtracing(vector<vector<char>>& board,int i,int j,string &word,int t) { //if(board[i][j] != word[t]) return; if(word[t]==board[i][j] && t==word.size()-1) { flag=true; } int m=board.size(); int n=board[0].size(); char ch=board[i][j]; if(board[i][j]==word[t]) { // cout<<board[i][j]<<endl; board[i][j]='#'; for(int k=0;k<4;k++) { int new_i=i+xx[k]; int new_j=j+yy[k]; if(new_i>=0 && new_i<m && new_j>=0 && new_j<n && board[new_i][new_j]!='#') { backtracing(board,new_i,new_j,word,t+1); } } board[i][j]=ch; } } };
JZ13 机器人的运动范围
链接:机器人的运动范围_牛客题霸_牛客网
链接:力扣
这道题也做过了,相当于二刷。
注意dfs没有回溯!!!!!
class Solution { public: //似乎也是回溯法,还是广度优先?广度优先应该更容易 int cnt=0;//cnt记录能走的格子数,[0,0]肯定能走 vector<int>xx={0,0,1,-1}; vector<int>yy={1,-1,0,0}; int movingCount(int m, int n, int k) { vector<vector<int>>v(m,vector<int>(n,0));//创建m行n列的地图 backtracing(v,0,0,m,n,k); return cnt; } bool can(int m,int n,int k) { int sum=0; int x=m,y=n; while(x) { sum+=x%10; x=x/10; } while(y) { sum+=y%10; y=y/10; } // cout<<m<<" "<<n<<"sum "<<sum<<endl; if(sum>k) { return false; } return true; } void backtracing( vector<vector<int>> &v,int i,int j,int m,int n,int k) { //递归停止条件 if(i<0 ||i>m ||j<0 ||j>n) { return; } cnt++; v[i][j]=1;//代表已经走过了 for(int t=0;t<4;t++) { int new_i=i+xx[t]; int new_j=j+yy[t]; if(new_i>=0 && new_i<m && new_j>=0 && new_j<n && can(new_i,new_j,k)&&v[new_i][new_j]==0) { backtracing(v,new_i,new_j,m,n,k); } } //v[i][j]=0;//回溯 } };
JZ14 剪绳子
链接:剪绳子_牛客题霸_牛客网
leecode:
应该是动态规划。
困得不行了,看不下去。
力扣
aa
a
a
a