链表
JZ6 从尾到头打印链表
思路:先顺序输出到栈里面 然后再以此从栈顶弹出即可
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
#include <vector>
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
stack<int> st;
while(head!=nullptr){
st.push(head->val);
head=head->next;
}
vector<int> res;
while(!st.empty()){
res.push_back(st.top());
st.pop();
}
return res;
}
};
JZ24 反转链表
思路:借助虚拟头结点进行头插法
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @return ListNode类
*/
ListNode* ReverseList(ListNode* head) {
// write code here
//头插法
ListNode* dummy = new ListNode(0);
ListNode* cur = head;
while(cur!=nullptr){
ListNode* next = cur->next;
//头插法
cur->next=dummy->next;
dummy->next=cur;
cur = next;
}
ListNode* res = dummy->next;
delete dummy;
return res;
}
};
JZ25 合并两个排序的链表
方法一:迭代法
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead1 ListNode类
* @param pHead2 ListNode类
* @return ListNode类
*/
// ListNode* dfs(ListNode* pHead1, ListNode* pHead2){
// }
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
// write code here
// 迭代写法
ListNode* dummp=new ListNode(0);
ListNode*pre =dummp;
while(pHead1!=nullptr&&pHead2!=nullptr){
if(pHead1->val<pHead2->val){
ListNode* temp = new ListNode(pHead1->val);
pre->next=temp;
pre=temp;
pHead1=pHead1->next;
}else{
ListNode* temp = new ListNode(pHead2->val);
pre->next=temp;
pre=temp;
pHead2=pHead2->next;
}
}
while(pHead1!=nullptr){
ListNode* temp = new ListNode(pHead1->val);
pre->next=temp;
pre=temp;
pHead1=pHead1->next;
}
while(pHead2!=nullptr){
ListNode* temp = new ListNode(pHead2->val);
pre->next=temp;
pre=temp;
pHead2=pHead2->next;
}
ListNode* res=dummp->next;
delete dummp;
return res;
}
};
方法二 递归:
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead1 ListNode类
* @param pHead2 ListNode类
* @return ListNode类
*/
// ListNode* dfs(ListNode* pHead1, ListNode* pHead2){
// }
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
// write code here
if(pHead1==nullptr && pHead2==nullptr){
return nullptr;
}else if(pHead1==nullptr && pHead2!=nullptr){
return pHead2;
}else if(pHead1!=nullptr && pHead2==nullptr){
return pHead1;
}
//
if(pHead1->val<pHead2->val){
//
ListNode* next1=pHead1->next;
// pHead1->next=nullptr;
pHead1->next=Merge(next1,pHead2);
return pHead1;
}
ListNode* next2=pHead2->next;
// pHead2->next=nullptr;
pHead2->next=Merge(pHead1,next2);
return pHead2;
}
};
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* cur1 = pHead1;
ListNode* cur2 = pHead2;
while(cur1!=cur2){
cur1= cur1==nullptr?pHead2:cur1->next;
cur2= cur2==nullptr?pHead1:cur2->next;
}
return cur2;
}
};
方法二
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
// 普通解法 就是先走多少步
ListNode* cur1 = pHead1;
int len1 =0;
while(cur1!=nullptr){
cur1=cur1->next;
len1++;
}
ListNode* cur2 = pHead2;
int len2 =0;
while(cur2!=nullptr){
cur2=cur2->next;
len2++;
}
int gap =abs(len1-len2);
// 保证pHead1指向的是长的链表
if(len1<len2){
ListNode* temp=pHead1;
pHead1=pHead2;
pHead2=temp;
}
cur1 = pHead1;
while(gap--){
cur1=cur1->next;
}
cur2 = pHead2;
while(cur1!=nullptr){
if(cur1==cur2){
return cur1;
}
cur1=cur1->next;
cur2=cur2->next;
}
return cur2;
}
};
JZ23 链表中环的入口结点
思路:快慢指针 循环体内 快指针每次走两步 慢指针每次走一步 能够相遇也就是说明有环 然后 慢指针从头开始 另外一个指针从相遇节点开始 判断是否再次相遇 不相遇 这两个指针 每次走一步 走到相遇点就是环入口。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
ListNode* slow,*fast;
slow=fast=pHead;
while(fast!=nullptr&&fast->next!=nullptr){
slow=slow->next;
fast=fast->next->next;
if(slow==fast){
// 存在环
ListNode* slow = pHead;
ListNode* cur = fast;
while(slow!=cur){
slow=slow->next;
cur=cur->next;
}
return cur;
}
}
return nullptr;
}
};
JZ35 复杂链表的复制
参考视频
思路:使用散列表 如下
unordered_map<RandomListNode*,RandomListNode*> mymap;
RandomListNode* cur = pHead;
while(cur!=nullptr){
mymap[cur]=new RandomListNode(cur->label);
cur=cur->next;
}
此时节点已经构造出来了 开始准备映射节点的next,以及random关系
完整代码:
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
// RandomListNode* dfs(RandomListNode* pHead) {
// if (pHead == nullptr) {
// return nullptr;
// }
// RandomListNode* newnode = new RandomListNode(pHead->label);
// cout << "val:" << pHead->label << endl;
// newnode->next = dfs(pHead->next);
// newnode->random = dfs(pHead->random);
// return newnode;
// }
public:
RandomListNode* Clone(RandomListNode* pHead) {
//
unordered_map<RandomListNode*,RandomListNode*> mymap;
RandomListNode* cur = pHead;
while(cur!=nullptr){
mymap[cur]=new RandomListNode(cur->label);
cur=cur->next;
}
cur = pHead;
while(cur!=nullptr){
if(cur->next){
mymap[cur]->next=mymap[cur->next];
}
if(cur->random){
mymap[cur]->random=mymap[cur->random];
}
cur=cur->next;
}
return mymap[pHead];
}
};
Z76 删除链表中重复的结点
思路:这里使用率pre以及cur 每次看cur以及cur->next是否相等 不相等 移动pre以及cur 如果相等 移动cur到本次循环不相等的地方
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead) {
ListNode* dummy = new ListNode(0);
dummy->next = pHead;
ListNode*pre = dummy;
ListNode*cur = pHead;
while(cur!=nullptr){
if(cur->next==nullptr || cur->next->val != cur->val){
// 准备下一次循环 pre/cur 都需要移动一格
pre=cur;
cur=cur->next;
}else{
while(cur->next!=nullptr && cur->val ==cur->next->val){
cur=cur->next;
}
ListNode* nextnode = cur->next;
// 直接跳过重复的节点 也就是pre->next直接next到不重复的节点(模拟删除) 注意pre没有移动 移动的是cur
pre->next = nextnode;
cur = nextnode;
}
}
return dummy->next;
}
};
JZ18 删除链表的节点
方法一:迭代法
方法二:递归
方法一
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @param val int整型
* @return ListNode类
*/
ListNode* deleteNode(ListNode* head, int val) {
// write code here
if(head==nullptr){
return nullptr;
}
if(head->val!=val){
head->next=deleteNode(head->next,val);
return head;
}
return deleteNode(head->next,val);
}
};
方法二:
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @param val int整型
* @return ListNode类
*/
ListNode* deleteNode(ListNode* head, int val) {
// write code here
ListNode* dummy =new ListNode(0);
dummy->next=head;
ListNode* pre = dummy;
ListNode* cur = head;
while(cur!=nullptr){
if(cur->val==val){
// 你不需要 free 或 delete 被删除的节点 题目已经指出来
// ListNode* delenode = cur;
cur=cur->next;
pre->next = cur;
}else{
pre=cur;
cur=cur->next;
}
}
return dummy->next;
}
};
二叉树
二叉树四部曲
1.确定是否需要返回值(和题目的递归函数函数是否有返回值无关)
2.确定遍历顺序(有返回值接的需要接住)
3.确定结束条件(注意是否存在中途直接return)
4.确定单层循环逻辑
J
Z55 二叉树的深度
思路:后序遍历
/*
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;
}
int leftdep = TreeDepth(pRoot->left);
int rightdep = TreeDepth(pRoot->right);
return max(leftdep,rightdep)+1;
}
};
JZ54 二叉搜索树的第k个节点
思路:中序遍历
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
#include <climits>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param proot TreeNode类
* @param k int整型
* @return int整型
*/
int ret=INT_MAX;
void dfs(TreeNode* proot, int &k){
if(proot==nullptr){
return;
}
dfs(proot->left,k);
k--;
if(k==0){
ret=proot->val;
}
dfs(proot->right,k);
}
int KthNode(TreeNode* proot, int k) {
// write code here
dfs(proot,k);
return ret==INT_MAX?-1:ret;
}
};
JZ7 重建二叉树
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param preOrder int整型vector
* @param vinOrder int整型vector
* @return TreeNode类
*/
TreeNode* reConstructBinaryTree(vector<int>& preOrder, vector<int>& vinOrder) {
// write code here
if(preOrder.size()==0){
return nullptr;
}
int val = preOrder[0];
preOrder.erase(preOrder.begin());
int inindex =0;
for(int i=0;i<vinOrder.size();i++){
if(vinOrder[i]==val){
inindex=i;
break;
}
}
/****** 下面这种写法 注意区间是左闭右开的******/
// 中序遍历的左部分
vector<int> vinLeftOrder(vinOrder.begin(),vinOrder.begin()+inindex);
// 中序遍历的右部分
vector<int> vinRightOrder(vinOrder.begin()+inindex+1,vinOrder.end());
// 先序遍历的左部分
vector<int> preLeftOrder(preOrder.begin(), preOrder.begin() +inindex);
// 先序遍历的右部分
vector<int> preRightOrder(preOrder.begin() +inindex, preOrder.end());
// cout<<"preLeftOrder.size()"<<preLeftOrder.size()<<" vinLeftOrder.size()"<<vinLeftOrder.size()<<" preRightOrder.size()"<<preRightOrder.size()<<" vinRightOrder.size()"<<vinRightOrder.size()<<endl;
TreeNode* root =new TreeNode(val);
root->left = reConstructBinaryTree(preLeftOrder,vinLeftOrder);
root->right = reConstructBinaryTree(preRightOrder,vinRightOrder);
return root;
}
};
JZ26 树的子结构
思路:先序遍历
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
bool dfs(TreeNode* pRoot1, TreeNode* pRoot2){
if(pRoot2==nullptr) return true;
if(pRoot1==nullptr) return false;
if(pRoot1->val!=pRoot2->val){
return false;
}
return dfs(pRoot1->left,pRoot2->left)&&dfs(pRoot1->right,pRoot2->right);
}
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
if(pRoot2==nullptr) return false;
if(pRoot1==nullptr) return false;
if(dfs(pRoot1,pRoot2)){
return true;
}
return HasSubtree(pRoot1->left,pRoot2)||HasSubtree(pRoot1->right,pRoot2);
}
};
JZ27 二叉树的镜像
/**
* 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){
return nullptr;
}
TreeNode* temp = pRoot->left;
pRoot->left=pRoot->right;
pRoot->right=temp;
Mirror(pRoot->left);
Mirror(pRoot->right);
return pRoot;
}
};
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*> qu;
vector<int> res;
if(root==nullptr){
return res;
}
qu.push(root);
while(!qu.empty()){
int len = qu.size();
for(int i=0;i<len;i++){
TreeNode* node = qu.front();
res.push_back(node->val);
qu.pop();
if(node->left){
qu.push(node->left);
}
if(node->right){
qu.push(node->right);
}
}
}
return res;
}
};
JZ33 二叉搜索树的后序遍历序列
先确定根节点 然后 找到第一个可以区分左右区间的 验证当前左右分支节点是否合理(大小) 然后递归
技巧 直接右分支的左边界初始化为1
int index = -1;
for (int i = 0; i < sequence.size(); i++) {
if (sequence[i] > val) {
index = i;
break;
}
}
class Solution {
public:
bool dfs(vector<int> sequence) {
if (sequence.size() <= 1) {
return true;
}
int val = sequence.back();
sequence.pop_back();
int index = -1;
for (int i = 0; i < sequence.size(); i++) {
if (sequence[i] > val) {
index = i;
break;
}
}
if (index == -1) {
// 没有右边 sequence已经处理过 移除过根节点了
return dfs(sequence);
}
for (int i = index; i < sequence.size(); i++) {
if (sequence[i] < val) {
return false;
}
}
vector<int> leftsequence(sequence.begin(), sequence.begin() + index);
vector<int> rightsequence(sequence.begin() + index, sequence.end());
return dfs(leftsequence) && dfs(rightsequence);
}
bool VerifySquenceOfBST(vector<int> sequence) {
if(sequence.size()==0){
return false;
}
return dfs(sequence);
}
};
上面可以发现测试用例里面 sequence是空的时候 不是搜索树 我觉得测试用例有问题 空的二叉树 应该也是二叉搜索树 在leetcodeLCR 152. 验证二叉搜索树的后序遍历序列中测试用例完善了这一点
leetcode代码因此可以更加简洁
class Solution {
public:
bool verifyTreeOrder(vector<int>& postorder) {
if(postorder.size()==0){
return true;
}
int rootval = postorder.back();
postorder.pop_back();
int index=postorder.size();
for(int i=0;i<postorder.size();i++){
if(postorder[i]>rootval){
index= i;
break;
}
}
// 左闭右开
vector<int> left(postorder.begin(),postorder.begin()+index);
vector<int> right(postorder.begin()+index,postorder.end());
for(int i=0;i<left.size();i++){
if(left[i]>rootval){
return false;
}
}
for(int i=0;i<right.size();i++){
if(right[i]<rootval){
return false;
}
}
return verifyTreeOrder(left)&&verifyTreeOrder(right);
}
};
JZ36 二叉搜索树与双向链表
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
stack<TreeNode*> st;
void dfs(TreeNode* pRootOfTree){
if(pRootOfTree==nullptr){
return;
}
dfs(pRootOfTree->right);
st.push(pRootOfTree);
dfs(pRootOfTree->left);
}
public:
TreeNode* Convert(TreeNode* pRootOfTree) {
if(pRootOfTree==nullptr){
return nullptr;
}
dfs(pRootOfTree);
TreeNode* dummy=new TreeNode(-1);
TreeNode* pre=dummy;
while(!st.empty()){
TreeNode* node = st.top();
st.pop();
cout<<"val:"<<node->val<<endl;
node->left=nullptr;
node->right=nullptr;
pre->right = node;
node->left = pre;
pre = node;
}
TreeNode* res= dummy->right;
res->left=nullptr;
return res;
}
};
JZ79 判断是不是平衡二叉树
/**
* 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 bool布尔型
*/
int dfs(TreeNode* pRoot) {
// write code here
if(pRoot==nullptr){
return 0;
}
int leftdep = dfs(pRoot->left);
int rightdep = dfs(pRoot->right);
if(leftdep==-1||rightdep==-1){
return -1;
}
if(abs(leftdep-rightdep)>1){
return -1;
}
int curdep =max(leftdep,rightdep)+1;
return curdep;
}
bool IsBalanced_Solution(TreeNode* pRoot) {
// write code here
int dep = dfs(pRoot);
return dep==-1?false:true;
}
};
JZ8 二叉树的下一个结点
JZ78 把二叉树打印成多行
/**
* 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 int整型vector<vector<>>
*/
vector<vector<int> > Print(TreeNode* pRoot) {
// write code here
vector<vector<int> > ret;
if(pRoot==nullptr){
return ret;
}
queue<TreeNode*> qu;
qu.push(pRoot);
while(!qu.empty()){
int len = qu.size();
vector<int> temp;
for(int i=0;i<len;i++){
TreeNode* node =qu.front();
qu.pop();
temp.push_back(node->val);
if(node->left){
qu.push(node->left);
}
if(node->right){
qu.push(node->right);
}
}
ret.push_back(temp);
}
return ret;
}
};
JZ37 序列化二叉树
这个题目和leetcode的题目是一样的 只不过给的函数返回值类型不一样而已 leetcode297二叉树的序列化与反序列化
leetcode:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec {
public:
// Encodes a tree to a single string.
void serializeHelper(TreeNode* root,string &str){
// 先序遍历
if(root==NULL){
str=str+"#"+",";
return;
}
str=str+to_string(root->val)+ ",";
serializeHelper(root->left,str);
serializeHelper(root->right,str);
}
string serialize(TreeNode* root) {
string str;
serializeHelper(root,str);
return str;
}
// Decodes your encoded data to tree.
vector<string> getVFromStr(string data){
vector<string> res;
string temp ="";
for(int i=0;i<data.size();i++){
if(data[i]==','){
res.push_back(temp);
temp.clear();
}else{
temp=temp+data[i];
}
}
return res;
}
TreeNode*DecodeTreeNodeFromV(vector<string> num,int &i){
if(num[i]=="#"){
i++;
return NULL;
}
TreeNode* node = new TreeNode(stoi(num[i]));
i++;
node->left = DecodeTreeNodeFromV(num,i);
node->right = DecodeTreeNodeFromV(num,i);
return node;
}
TreeNode* deserialize(string data) {
vector<string> num = getVFromStr(data);
// for(auto item:num){
// cout<<item<<" ";
// }
// cout<<endl;
int startindex =0;
TreeNode* root = DecodeTreeNodeFromV(num,startindex);
return root;
}
};
// Your Codec object will be instantiated and called as such:
// Codec ser, deser;
// TreeNode* ans = deser.deserialize(ser.serialize(root));
回看牛客里面是char参数 也就是见char 和string相互转换就可以将代码直接复制到牛客上面了
str==》char *
string str =".."
char * retc =new char[str.length()+1];
strcpy(retc, str.c_str());
char * ==》string
char *pc;
string data(pc);
完整代码:
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
#include <cstring>
class Solution {
public:
void serializeHelper(TreeNode* root,string &str){
// 先序遍历
if(root==NULL){
str=str+"#"+",";
return;
}
str=str+to_string(root->val)+ ",";
serializeHelper(root->left,str);
serializeHelper(root->right,str);
}
string serialize(TreeNode* root) {
string str;
serializeHelper(root,str);
return str;
}
// Decodes your encoded data to tree.
vector<string> getVFromStr(string data){
vector<string> res;
string temp ="";
for(int i=0;i<data.size();i++){
if(data[i]==','){
res.push_back(temp);
temp.clear();
}else{
temp=temp+data[i];
}
}
return res;
}
TreeNode*DecodeTreeNodeFromV(vector<string> num,int &i){
if(num[i]=="#"){
i++;
return NULL;
}
TreeNode* node = new TreeNode(stoi(num[i]));
i++;
node->left = DecodeTreeNodeFromV(num,i);
node->right = DecodeTreeNodeFromV(num,i);
return node;
}
TreeNode* deserialize(string data) {
vector<string> num = getVFromStr(data);
// 测试打印
// for(auto item:num){
// cout<<item<<" ";
// }
// cout<<endl;
int startindex =0;
TreeNode* root = DecodeTreeNodeFromV(num,startindex);
return root;
}
char* Serialize(TreeNode *root) {
string str =serialize(root);
char * retc =new char[str.length()+1];
strcpy(retc, str.c_str());
return retc;
}
TreeNode* Deserialize(char *str) {
string data(str);
return deserialize(data);
}
};
JZ84 二叉树中和为某一值的路径(三)
思路:先序遍历二叉树 然后争对每个节点再次先序遍历
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @param sum int整型
* @return int整型
*/
int count =0;
void dfs(TreeNode* root, int sum){
if(root==nullptr){
return;
}
sum=sum-root->val;
if(sum==0){
count++;
}
dfs(root->left,sum);
dfs(root->right,sum);
}
void preorder(TreeNode* root, int sum){
if(root==nullptr){
return;
}
// write code here
dfs(root,sum);
preorder(root->left,sum);
preorder(root->right,sum);
}
int FindPath(TreeNode* root, int sum) {
// write code here
preorder(root,sum);
return count;
}
};
JZ86 在二叉树中找到两个节点的最近公共祖先
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @param o1 int整型
* @param o2 int整型
* @return int整型
*/
TreeNode* dfs(TreeNode* root, int o1, int o2){
if(root==nullptr){
return nullptr;
}
if(root->val==o1||root->val==o2){
return root;
}
TreeNode* leftchild = dfs(root->left,o1,o2);
TreeNode* rightchild = dfs(root->right,o1,o2);
if(leftchild==nullptr && rightchild==nullptr){
return nullptr;
}else if(leftchild!=nullptr && rightchild==nullptr){
return leftchild;
}else if(leftchild==nullptr && rightchild!=nullptr){
return rightchild;
}
return root;
}
int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
// write code here
TreeNode* node = dfs(root,o1,o2);
return node->val;
}
};
JZ68 二叉搜索树的最近公共祖先
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @param p int整型
* @param q int整型
* @return int整型
*/
// -1 就是代表空
TreeNode* dfs(TreeNode* root, int p, int q){
if(root==nullptr){
return nullptr;
}
if(root->val == p || root->val == q){
return root;
}
if(root->val>p && root->val>q){
return dfs(root->left,p,q);
}
if(root->val<p && root->val<q){
return dfs(root->right,p,q);
}
// 左右两边各一个 也就是说此时root就是最近公共祖先
return root;
}
int lowestCommonAncestor(TreeNode* root, int p, int q) {
// write code here
TreeNode* ndoe = dfs(root,p,q);
return ndoe->val;
}
};
队列 & 栈
JZ9 用两个栈实现队列
思路:stack1只负责push
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
if(stack2.empty()){
while(!stack1.empty()){
stack2.push(stack1.top());
stack1.pop();
}
}
int val = stack2.top();
stack2.pop();
return val;
}
private:
// 插入
stack<int> stack1;
stack<int> stack2;
};
JZ30 包含min函数的栈
思路: st1 只负责push 每次栈st2的时候 需要比较st2栈顶数据 压入小数据
class Solution {
public:
void push(int value) {
st1.push(value);
if(!st2.empty()){
int top= st2.top();
if(top>value){
st2.push(value);
}else{
st2.push(top);
}
}else{
st2.push(value);
}
}
void pop() {
st1.pop();
st2.pop();
}
int top() {
return st1.top();
}
int min() {
return st2.top();
}
stack<int> st1;
stack<int> st2;
};
JZ31 栈的压入、弹出序列
刚开始没有理清思路 以为 push的元素 如果在pop中出来了 那么push该之前的元素也一定出来了
发现还有这种情况
[2,1,0],[1,2,0] 明显这个是多余的 但是和思路不符合 所以上面这个思路是错的
正确思路:借助栈 每次入st栈后 如果发现栈顶元素和popV中将要出栈的元素一致 直接st.pop 直到和opV中将要出栈的元素不一致时候 进入下一轮循环 最终直接判断st是否为空即可
可以参考视频;
完整代码:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pushV int整型vector
* @param popV int整型vector
* @return bool布尔型
*/
bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
// write code here
stack<int> st;
int popindex =0;
for(int i=0;i<pushV.size();i++){
// if(st.empty()){
st.push(pushV[i]);
// }
while(!st.empty() && st.top() ==popV[popindex]){
st.pop();
popindex++;
}
}
return st.empty();
}
};
JZ73 翻转单词序列
JZ59 滑动窗口的最大值
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param num int整型vector
* @param size int整型
* @return int整型vector
*/
vector<int> maxInWindows(vector<int>& num, int size) {
// write code here
vector<int> res;
// 单纯的是因为测试用例里面有size是0 因此需要单独拎出来
if(size==0){
return res;
}
// 不严格的单调递减队列(使用双向队列deque) 队列里面存元素下标 弹出条件是 num[i] >num[qu.back()] 此时弹出qu.back()
deque<int> qu;
for(int i=0;i<num.size();i++){
while(!qu.empty()&&num[i]>num[qu.back()]){
qu.pop_back();
}
qu.push_back(i);
if(qu.back()-qu.front()+1>size){
qu.pop_front();
}
if(i+1>=size){
res.push_back(num[qu.front()]);
}
}
return res;
}
};
搜索算法
JZ53 数字在升序数组中出现的次数
寻找左边界的时候
int mid = (left+right)/2;
需要注意寻找右边界的时候
int mid = (left+right+1)/2;
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @param k int整型
* @return int整型
*/
int GetNumberOfK(vector<int>& nums, int k) {
// write code here
if(nums.size()==0){
return 0;
}
// 寻找左边界
int left =0;
int right =nums.size()-1;
while(left<right){
// 这种写法 会向左边靠拢
int mid = (left+right)/2;
if(nums[mid]>k){
right=mid -1;
}else if(nums[mid]<k){
left=mid+1;
}else if(nums[mid]==k){
right=mid;
}
}
// cout<<"left:"<<left<<endl;
if(nums[left]!=k){
return 0;
}
int leftindex = left;
// 有边界
left =0;
right =nums.size()-1;
while(left<right){
// 此时相等的时候 会向右边靠拢
int mid = (left+right+1)/2;
if(nums[mid]>k){
right=mid -1;
}else if(nums[mid]<k){
left=mid+1;
}else if(nums[mid]==k){
left=mid;
}
}
// cout<<"right"<<left<<endl;
int rightindex = left;
return rightindex-leftindex+1;
}
};
JZ11 旋转数组的最小数字
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型
*/
int minNumberInRotateArray(vector<int>& nums) {
// write code here
int left = 0;
int right = nums.size()-1;
while(left<right){
int mid = (left+right)/2;
if(nums[mid]>nums[right]){
left=mid+1;
}else if(nums[mid]<nums[right]){
right = mid;
}else{
right--;
}
cout<<"left:"<<left<<endl;
}
return nums[left];
}
};
JZ38 字符串的排列
思路:回溯算法 排列问题 并且需要数层去重 (先排序 再借助used[i]数组)
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param str string字符串
* @return string字符串vector
*/
vector<string> res;
string path;
void backtracking(string str,vector<bool> &used){
if(path.size()==str.size()){
res.push_back(path);
// return;
}
for(int i=0;i<str.size();i++){
if(i-1>=0&&str[i]==str[i-1]&&used[i-1]==false){
continue;
}
if(used[i]==true){
continue;
}
used[i]=true;
path=path+str[i];
// cout<<"i:"<<i<<endl;
backtracking(str,used);
path.pop_back();
used[i]=false;
}
}
vector<string> Permutation(string str) {
// write code here
// 数层去重 全排列
// 先排序
sort(str.begin(),str.end(),[](char a,char b){
return a<b;
});
vector<bool> used(str.size(),false);
backtracking(str, used);
return res;
}
};
JZ44 数字序列中某一位的数字
动态规划
JZ85 连续子数组的最大和(二)
思路:先用动态规范求的每个结尾的最大和 然后遍历dp 从最大和下标往前找 看有没有是最大和 找到后比较最大长度即可
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> FindGreatestSumOfSubArray(vector<int>& array) {
// write code here
// // dp[i]以array[i]的结尾的连续的最长和
// if(dp[i-1]>=0){
// dp[i]=dp[i-1]+array[i];
// }else{
// dp[i]=array[i];
// }
// // 初始化
// dp[0]=array[0];
// // 遍历顺序 从左到右
// // 返回值 遍历dp[i] 找到最大和的结尾下边 向前查找
// //
vector<int> dp(array.size(),0);
dp[0]=array[0];
for(int i=1;i<array.size();i++){
if(dp[i-1]>=0){
dp[i]=dp[i-1]+array[i];
}else{
dp[i]=array[i];
}
}
// int rightindex =0;
int summax=INT_MIN;
vector<int> rightindexList;
for(int i=0;i<dp.size();i++){
if(dp[i]>summax){
rightindexList.clear();
rightindexList.push_back(i);
summax=dp[i];
}else if(dp[i]==summax){
rightindexList.push_back(i);
}
}
// int maxlen =0;
vector<int> res;
for(auto rightindex: rightindexList){
int currntsum = 0;
vector<int> temp;
for(int j=rightindex;j>=0;j--){
currntsum=currntsum+array[j];
temp.push_back(array[j]);
if(currntsum==summax){
// 取最大的
if(temp.size()>res.size()){
res=temp;
}
}
}
}
reverse(res.begin(),res.end());
return res;
}
};
JZ69 跳台阶
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param number int整型
* @return int整型
*/
int jumpFloor(int number) {
// write code here
// dp[i] 跳上第i借台阶 有dp[i]中方法
// dp[i]=dp[i-1]+dp[i-2];
// dp[0],dp[1]
// // 从左到右
// dp[n]
vector<int> dp(number+1,0);
dp[0]=1;
dp[1]=1;
for(int i=2;i<=number;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[number];
}
};
JZ10 斐波那契数列
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @return int整型
*/
int Fibonacci(int n) {
// write code here
// dp[i]=dp[i-1]+dp[i-2];
vector<int> dp(n+1,0);
dp[0]=0;
dp[1]=1;
for(int i=2;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
};
JZ71 跳台阶扩展问题
思路:完全背包 也就是元素可以重复 并且 是排列问题l
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param number int整型
* @return int整型
*/
int jumpFloorII(int number) {
// write code here
// 1,2,3...n 组成和为n的不同排列数有多少==》完全背包 也就是元素可以重复 并且 是排列问题
vector<int> dp(number+1,0);
dp[0]=1;
for(int i=1;i<=number;i++){
for(int j=1;j<=number;j++){
if(i-j>=0){
dp[i]=dp[i]+dp[i-j];
}
}
}
return dp[number];
}
};
JZ70 矩形覆盖
#include <vector>
class Solution {
public:
int rectCover(int number) {
// dp[n]..
vector<int> dp(number+1,0);
dp[1]=1;
dp[2]=2;
for(int i=3;i<=number;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[number];
}
};
JZ47 礼物的最大价值
思路:dp[i][j]=max(dp[i][j-1],dp[i-1][j])+grid[i][j]; 看到这个就想到遍历顺序 从上到下 从左到右
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param grid int整型vector<vector<>>
* @return int整型
*/
int maxValue(vector<vector<int> >& grid) {
// write code here
// dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
// 初始化
// 第一行
vector<vector<int>> dp(grid.size(),vector<int>(grid[0].size(),0));
int hang=0;
for(int j=0;j<grid[0].size();j++){
hang=hang+grid[0][j];
dp[0][j]=hang;
}
int lie=0;
for(int i=0;i<grid.size();i++){
lie=lie+grid[i][0];
dp[i][0]=lie;
}
for(int i=1;i<grid.size();i++){
for(int j=1;j<grid[0].size();j++){
dp[i][j]=max(dp[i][j-1],dp[i-1][j])+grid[i][j];
}
}
return dp[grid.size()-1][grid[0].size()-1];
}
};
JZ48 最长不含重复字符的子字符串
#include <vector>
using namespace std;
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串
* @return int整型
*/
int lengthOfLongestSubstring(string s) {
// write code here
int count=0;
unordered_set<char> myset;
int i=0;
for(int j=0;j<s.size();j++){
while(myset.count(s[j])!=0){
myset.erase(s[i]);
i++;
}
myset.insert(s[j]);
count=max(count,j-i+1);
}
return count;
}
};
JZ46 把数字翻译成字符串
方法一:回溯法 -字符串的分割类型
// 回溯算法 字符串的分割
int count =0;
void backtracking(string nums,int statri){
if(statri==nums.size()){
count++;
return;
}
for(int i=statri;i<nums.size();i++){
string substr=nums.substr(statri,i-statri+1);
// cout<<"-nums-:"<<nums<<"--"<<statri<< "--"<<i<<"--长度"<< i-statri+1<< " substr:"<<stoi(substr)<<endl;
if(stoi(substr)<=0||stoi(substr)>26){
// 没有意义 不用再向后面切割了
break;
}
backtracking(nums,i+1);
}
}
int solve(string nums) {
// write code here
backtracking(nums,0);
return count;
}
方法二:动态规范
状态转移方程 dp[i]=dp[i-1]+dp[i-2];
但是注意以下前提
// dp[i]=dp[i-1]+dp[i-2];
int val1,val2;
if(nums[i]=='0'){
val1=0;
}else{
val1=dp[i-1];
}
string str2;
str2=str2+nums[i-1]+nums[i];
if(stoi(str2)<10||stoi(str2)>=27){
val2=0;
}else{
val2=dp[i-2];
}
dp[i]=val1+val2;
完整代码
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 解码
* @param nums string字符串 数字串
* @return int整型
*/
int solve(string nums) {
// write code here
// backtracking(nums,0);
// return count;
// dp[i]=dp[i-1]+dp[i-2]
vector<int> dp(nums.size(),0);
if(nums[0]=='0'){
dp[0]=0;
}else{
dp[0]=1;
}
string temp = nums.substr(0,2);
if(stoi(temp)>=1&&stoi(temp)<=26 && temp[1]!='0'){
dp[1]=dp[0]+1;
}else{
dp[1]=dp[0];
}
for(int i=2;i<nums.size();i++){
// dp[i]=dp[i-1]+dp[i-2];
int val1,val2;
if(nums[i]=='0'){
val1=0;
}else{
val1=dp[i-1];
}
string str2;
str2=str2+nums[i-1]+nums[i];
if(stoi(str2)<10||stoi(str2)>=27){
val2=0;
}else{
val2=dp[i-2];
}
dp[i]=val1+val2;
}
return dp[nums.size()-1];
}
};
图算法(主要就是回溯)
JZ12 矩阵中的路径
图算法里面代码:
vector<vector<int>> dxy = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
....
for (int i = 0; i < dxy.size(); i++) {
赋值1
赋值2
dfs(..);
回溯赋值2
回溯赋值1
}
...
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param matrix char字符型vector<vector<>>
* @param word string字符串
* @return bool布尔型
*/
vector<vector<int>> dxy = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
bool isValid(vector<vector<char>>& matrix,int itemi,int itemj, int equalindex, string word){
// 是否越界
if (itemi < 0 || itemi >= matrix.size() || itemj < 0 || itemj >= matrix[0].size() ) {
return false;
}
// 是否单词匹配
if(matrix[itemi][itemj]!=word[equalindex]){
return false;
}
return true;
}
bool dfs(vector<vector<char> >& matrix, vector<vector<bool> > used, int starti,
int startj, int equalindex, string word) {
if (equalindex == word.size()) {
return true;
}
for (int i = 0; i < dxy.size(); i++) {
int itemi = starti + dxy[i][0];
int itemj = startj + dxy[i][1];
if (!isValid(matrix, itemi, itemj, equalindex, word)) {
continue;
}
if (used[itemi][itemj] == true) {
// cout<<"该位置 已经遍历过了"<<" itemi: "<<itemi<<" itemj: "<<itemj<<endl;
continue;
}
used[itemi][itemj] = true;
if(dfs(matrix, used, itemi, itemj, equalindex+1,word)){
return true;
}
used[itemi][itemj] = false;
}
return false;
}
bool hasPath(vector<vector<char> >& matrix, string word) {
// write code here
vector<vector<bool> > used(matrix.size(), vector<bool>(matrix[0].size(),
false));
for (int i = 0; i < matrix.size(); i++) {
for (int j = 0; j < matrix[0].size(); j++) {
if(word[0]!=matrix[i][j]){
continue;
}
used[i][j] = true;
if(dfs(matrix, used, i, j, 1,word)){
return true;
};
used[i][j] = false;
}
}
return false;
}
};
JZ13 机器人的运动范围
#include <vector>
class Solution {
public:
vector<vector<int>> dxy{{0,1},{0,-1},{1,0},{-1,0}};
int getValueFrIndex(int start){
int ret =0;
while(start!=0){
ret=ret+start%10;
start=start/10;
}
return ret;
}
bool isValid(vector<vector<int>> matrix,int starti,int startj,int threshold){
if(starti<0||starti>=matrix.size() || startj<0||startj>=matrix[0].size()){
return false;
}
if(getValueFrIndex(starti)+getValueFrIndex(startj)>threshold){
return false;
}
return true;
}
void dfs(vector<vector<int>> &matrix,int starti,int startj,int &count,int threshold){
for(int i=0;i<dxy.size();i++){
int itemi = starti+dxy[i][0];
int itemj = startj+dxy[i][1];
if(!isValid(matrix,itemi,itemj,threshold)){
continue;
}
// 之前访问过
if(matrix[itemi][itemj]==-1){
continue;
}
matrix[itemi][itemj]=-1;
count++;
dfs(matrix,itemi,itemj,count,threshold);
}
}
int movingCount(int threshold, int rows, int cols) {
vector<vector<int>> matrix(rows,vector<int>(cols,0));
int count =1;
matrix[0][0]=-1;
dfs(matrix,0,0,count,threshold);
// ************输出matrix************
// for(int i=0;i<matrix.size();i++){
// for(int j=0;j<matrix[0].size();j++){
// cout<<matrix[i][j]<<" ";
// }
// cout<<endl;
// }
return count;
}
};
JZ3 数组中重复的数字
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型vector
* @return int整型
*/
int duplicate(vector<int>& numbers) {
// write code here
// 思路:每次将元素放到正确的位置上面
for(int i=0;i<numbers.size();i++){
while(numbers[i]!=i &&numbers[i]!=numbers[numbers[i]]){
int index1 =i;
int index2=numbers[i];
int temp =numbers[index1];
numbers[index1]=numbers[index2];
numbers[index2] = temp;
}
if(numbers[i]!=i){
return numbers[i];
}
}
return -1;
}
};
JZ51 数组中的逆序对
JZ40 最小的K个数
#include <functional>
#include <queue>
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param input int整型vector
* @param k int整型
* @return int整型vector
*/
vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
// write code here
// priority_queue<int,vector<int>,less<int>> qu;
priority_queue<int,vector<int>,less<int>> qu;
for(int i=0;i<input.size();i++){
qu.push(input[i]);
if(qu.size()>k){
qu.pop();
}
}
vector<int> res;
while(!qu.empty()){
res.push_back(qu.top());
qu.pop();
}
reverse(res.begin(),res.end());
return res;
}
};
JZ41 数据流中的中位数
#include <functional>
#include <queue>
class Solution {
public:
void balance(priority_queue<int,vector<int>,less<int>> &maxqu,priority_queue<int,vector<int>,greater<int>> &minqu){
if(abs((int)(maxqu.size()-minqu.size()))<=1){
return;
}
if(maxqu.size()>minqu.size()){
minqu.push(maxqu.top());
maxqu.pop();
}else{
maxqu.push(minqu.top());
minqu.pop();
}
}
void Insert(int num) {
if(minqu.size()==0){
minqu.push(num);
return;
}
if(maxqu.size()==0){
if(num>minqu.top()){
// 需要减min里面的堆顶元素出堆 放到maxqu里面
int topvalue = minqu.top();
maxqu.push(topvalue);
minqu.pop();
minqu.push(num);
}else{
maxqu.push(num);
}
return;
}
if(num>minqu.top()){
minqu.push(num);
}else{
maxqu.push(num);
}
balance(maxqu,minqu);
}
double GetMedian() {
// cout<<"maxqu:"<<maxqu.size()<<"minqu:"<<minqu.size()<<endl;
if(maxqu.size()>minqu.size()){
return maxqu.top();
} else if(maxqu.size()<minqu.size()){
return minqu.top();
}else{
int va1=maxqu.top();
int va2= minqu.top();
// cout<<"va1:"<<va1<<"va2:"<<va2<<endl;
return ((float)va1+va2)/2;
}
}
priority_queue<int,vector<int>,less<int>> maxqu;
priority_queue<int,vector<int>,greater<int>> minqu;
};
位运算
class Solution {
public:
int Add(int num1, int num2)
{
// 进位
int n1 =(num1&num2)<<1;
// 不进位的值
int n2=num1^num2;
return n1==0?n2:Add(n1,n2);
}
};
JZ15 二进制中1的个数
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @return int整型
*/
int NumberOf1(int n) {
// write code here
int count =0;
while(n!=0){
n=n&(n-1);
count++;
}
return count;
}
};
JZ16 数值的整数次方
JZ56 数组中只出现一次的两个数字
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型vector
*/
vector<int> FindNumsAppearOnce(vector<int>& nums) {
// write code here
int res1=0;
for(auto num:nums){
res1=res1^num;
}
// res1二进制右边的第一个1
int rightone = 1;
//找到两个数不相同的第一位
while((rightone & res1) == 0)
rightone <<= 1;
int a=0;
int b=0;
for(auto num:nums){
cout<<"num:"<<num<<" --------------:"<<endl;
if((num&rightone)==rightone){
a=a^num;
}else{
b=b^num;
}
}
if(a<b){
return {a,b};
}
return {b,a};
}
};
JZ64 求1+2+3+…+n
class Solution {
public:
int sum=0;
int Sum_Solution(int n) {
(n!=0) && Sum_Solution(n-1);
sum=sum+n;
// cout<<"sum:"<<sum<<endl;
return sum;
}
};
模拟
JZ29 顺时针打印矩阵
这种图的遍历
遍历上下左右
vector<vector<int>> dxy{{0,1},{1,0},{0,-1},{-1,0}};
backtrack中
for(int i=0;i<dxy.size();i++){
....
}
完整代码
class Solution {
public:
vector<int> res;
vector<vector<int>> dxy{{0,1},{1,0},{0,-1},{-1,0}};
bool isValid(vector<vector<int> > &matrix,int itenmi,int itenmj){
if(itenmi<0||itenmi>=matrix.size()||itenmj<0||itenmj>=matrix[0].size()){
return false;
}
return true;
}
void backtracking(vector<vector<int>> &matrix,vector<vector<bool>>& used,int starti,int startj,int fangxiang){
for(int i=0;i<dxy.size();i++){
fangxiang=(fangxiang+i)%4;
int itenmi = starti+dxy[fangxiang][0];
int itenmj = startj+dxy[fangxiang][1];
if(!isValid(matrix, itenmi, itenmj)){
continue;
}
if(used[itenmi][itenmj]==true){
continue;
}
used[itenmi][itenmj]=true;
res.push_back(matrix[itenmi][itenmj]);
backtracking(matrix,used,itenmi,itenmj,fangxiang);
}
}
vector<int> printMatrix(vector<vector<int> > matrix) {
// 单纯是因为测试用例有[[]] 因此需要单独拎出来
if(matrix.size()==0||matrix[0].size()==0){
return {};
}
vector<vector<bool>> used(matrix.size(),vector<bool>(matrix[0].size(),false));
used[0][0]=true;
res.push_back(matrix[0][0]);
backtracking(matrix,used,0,0,0);
return res;
}
};
JZ61 扑克牌顺子
思路:maxright-minleft<=4 另外 不存在初0以外的任何重复数字
class Solution {
public:
bool IsContinuous( vector<int> nums )
{
int minleft =INT_MAX;
int maxright=INT_MIN;
unordered_set<int> myset;
for(int i=0;i<nums.size();i++){
if(nums[i]==0){
continue;
}
if(myset.count(nums[i])>0){
return false;
}
myset.insert(nums[i]);
minleft=min(minleft,nums[i]);
maxright=max(maxright,nums[i]);
}
return maxright-minleft<=4;
}
};
*JZ20 表示数值的字符串*
其他算法
JZ66 构建乘积数组
思路动态规划
res[i]=dpleft[i]*dpright[i];
完整代码
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param A int整型vector
* @return int整型vector
*/
vector<int> multiply(vector<int>& A) {
// write code here
vector<int> dpleft(A.size(),0);
dpleft[0]=1;
for(int i=1;i<A.size();i++){
dpleft[i]=dpleft[i-1]*A[i-1];
}
vector<int> dpright(A.size(),0);
dpright[A.size()-1]=1;
for(int j=A.size()-2;j>=0;j--){
dpright[j]=dpright[j+1]*A[j+1];
}
vector<int> res(A.size(),0);
for(int i=0;i<A.size();i++){
res[i]=dpleft[i]*dpright[i];
}
return res;
}
};
JZ50 第一个只出现一次的字符
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param str string字符串
* @return int整型
*/
int FirstNotRepeatingChar(string str) {
// write code here
unordered_map<int,int> mymap;
for(auto c:str){
mymap[c]++;
}
for(int i=0;i<str.size(); i++){
if(mymap[str[i]]==1){
return i;
}
}
return -1;
}
};
JZ5 替换空格
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串
* @return string字符串
*/
string replaceSpace(string s) {
// write code here
string str;
for(auto c:s){
if(c==' '){
str=str+"%20";
}else{
str=str+c;
}
}
return str;
}
};
JZ21 调整数组顺序使奇数位于偶数前面(一)
JZ39 数组中出现次数超过一半的数字
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
//使用投票法
int count=0;
int ret=0;
for(int i=0;i<numbers.size();i++)
{
if(count==0)
{
ret=numbers[i];
}
if(ret==numbers[i])
{
count++;
}else{
count--;
}
}
return ret;
// 题目说一定有众数 并且众数》numbers.size()/2 因此不需要下面的代码
// // cout<<"ret="<<ret<<endl;
// int targetCount=0;
// for(int i=0;i<numbers.size();i++)
// {
// if(numbers[i]==ret)
// {
// targetCount++;
// }
// }
// return targetCount>numbers.size()/2? ret:0;
}
};
JZ45 把数组排成最小的数
在内置函数中
auto cmp=[](int a,int b){
return to_string(a)+to_string(b) <to_string(b)+to_string(a)
完整代码
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型vector
* @return string字符串
*/
string PrintMinNumber(vector<int>& numbers) {
// write code here
sort(numbers.begin(),numbers.end(),[](int a,int b){
return to_string(a)+to_string(b) <to_string(b)+to_string(a);
});
string str;
for(auto num:numbers){
str=str+to_string(num);
}
return str;
}
};
JZ49 丑数
class Solution {
public:
int nthUglyNumber(int n) {
vector<int> dp(n+1,0);
dp[1]=1;
int a=1;
int b=1;
int c =1;
for(int i=2;i<=n;i++){
dp[i]=min({dp[a]*2,dp[b]*3,dp[c]*5});
if(dp[i]==dp[a]*2){
a++;
}
if(dp[i]==dp[b]*3){
b++;
}
if(dp[i]==dp[c]*5){
c++;
}
}
for(auto val:dp){
cout<<val<<" ";
}
return dp[n];
}
};
JZ74 和为S的连续正数序列
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param sum int整型
* @return int整型vector<vector<>>
*/
vector<vector<int> > FindContinuousSequence(int sum) {
// write code here
int i=1;
int currentsum =0;
vector<vector<int> > res;
for(int j=1;j<=sum-1;j++){
currentsum=currentsum+j;
while(currentsum>sum){
currentsum=currentsum-i;
i++;
}
if(currentsum==sum){
vector<int> tempv;
for(int tempi=i;tempi<=j;tempi++){
tempv.push_back(tempi);
}
res.push_back(tempv);
}
}
return res;
}
};
JZ57 和为S的两个数字
#include <vector>
class Solution {
public:
vector<int> FindNumbersWithSum(vector<int> array,int sum) {
//
unordered_set<int> myset;
for(int i=0;i<array.size();i++){
int target = sum-array[i];
if(myset.count(target)>0){
return vector<int>{array[i],target};
}
myset.insert(array[i]);
}
return {};
}
};
JZ58 左旋转字符串
方法一:不借助额外数组进行自身翻转(掌握)
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param str string字符串
* @param n int整型
* @return string字符串
*/
string LeftRotateString(string str, int n) {
// write code here
if(str.size()==0){
return "";
}
n=n%str.size();
reverse(str.begin(),str.end());
// cout<<str<<endl;
reverse(str.end()-n,str.end());
// cout<<str<<endl;
reverse(str.begin(),str.end()-n);
// cout<<str<<endl;
return str;
}
};
方法二:直接找到左半边 右半边进行拼接
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param str string字符串
* @param n int整型
* @return string字符串
*/
string LeftRotateString(string str, int n) {
if(str.size()==0){
return "";
}
// write code here
int len = n%str.size();
string temp1 = str.substr(0,len);
string temp2 = str.substr(len);
return temp2+temp1;
}
};
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @param m int整型
* @return int整型
*/
int dfs(vector<int> &nums,int m){
if(nums.size()==1){
return nums[0];
}
int index = (m-1)%nums.size();
vector<int> left(nums.begin(),nums.begin()+index);
vector<int> right(nums.begin()+index+1,nums.end());
right.insert(right.end(), left.begin(), left.end());
return dfs(right,m);
}
int LastRemaining_Solution(int n, int m) {
// write code here
vector<int> nums;
for(int i=0;i<n;i++){
nums.push_back(i);
}
return dfs(nums,m);
}
};
JZ75 字符流中第一个不重复的字符
class Solution
{
vector<char> m_v;
map <char,int> my_map ; //保存每个字母出现的次数
public:
//Insert one char from stringstream
void Insert(char ch)
{
if(my_map.count(ch)==0)
{
m_v.push_back(ch);
}
my_map[ch]++;
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce() {
for(char c:m_v)
{
if(my_map[c]==1)
{
return c;
}
}
return '#';
}
};
JZ14 剪绳子
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @return int整型
*/
int cutRope(int n) {
// write code here
vector<int> dp(n+1,0);
dp[1]=1;
dp[2]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=i/2;j++){
dp[i]=max({dp[i],dp[i-j]*j,(i-j)*j});
}
}
return dp[n];
}
};