写在前面
此博客记录自己在剑指的刷题过程中所有通过的代码,目的在于监督自己每天刷题。持续刷题,持续更新。每天都要记得好好刷题鸭!
通过的代码记录
(1)JZ2 替换空格
这里是考察的字符数组的用法吧,我用了string,网上通用的解法没有引入string。
class Solution {
public:
void replaceSpace(char *str,int length) {
string ans="";
char* str2;
for(int i=0;i<strlen(str);i++)
{
if(str[i]!=' ')
ans+=str[i];
else
{
ans+="%20";
}
}
str2=(char*) ans.c_str();
strcpy(str,str2);
}
};
(2)JZ3 从尾到头打印链表
这里我是先反转单链表,再按照头到尾打印链表,网上通用的解法是直接头到尾打印,存到vector中再反转reverse,vector有这个函数。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int>ans;
ListNode *lastNode=NULL;
ListNode *newHead;
ListNode *nhead=head;
while(nhead!=NULL)
{
newHead=nhead;
nhead=nhead->next;
newHead->next=lastNode;
lastNode=newHead;
}
while(newHead!=NULL)
{
ans.push_back(newHead->val);
newHead=newHead->next;
}
return ans;
}
};
(3)JZ3 重建二叉树
这个就是很重要的题目了,算是基础题,这是通用解法。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
TreeNode* root=CreateTree(0,pre.size()-1,0,vin.size()-1,pre,vin);
return root;
}
TreeNode* CreateTree(int pb,int pe,int vb,int ve,vector<int> pre,vector<int> vin)
{
int index;
if(pb<=pe)
{
for(int i=0;i<vin.size();i++)
{
if(vin[i]==pre[pb])
index=i;
}
TreeNode* node=new TreeNode(pre[pb]);
node->left=CreateTree(pb+1,pb+index-vb, vb,index-1,pre,vin);
node->right=CreateTree(pb+index-vb+1,pe,index+1,ve,pre,vin);
return node;
}
return NULL;
}
};
(4)JZ5 用两个栈实现队列
这个题目我的代码跟网上的有些不同,不过基本思路都是一样的。
class Solution
{
public:
void push(int node) {
while(!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
stack1.push(node);
while(!stack2.empty())
{
stack1.push(stack2.top());
stack2.pop();
}
}
int pop() {
int data=stack1.top();
stack1.pop();
return data;
}
private:
stack<int> stack1;
stack<int> stack2;
};
(5)JZ8 跳台阶
这个题目就是考察的递归吧,也算是较为基础的。
class Solution {
public:
int ans=0;
int jumpFloor(int number) {
jump(0,number);
return ans;
}
void jump(int num,int number)
{
if(num==number)
{
ans++;
return ;
}
if((num+2)>number)
{
jump(num+1,number);
}
else if((num+2)<=number)
{
jump(num+1,number);
jump(num+2,number);
}
}
};
(6)JZ14 链表中倒数第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) {
if(pListHead==NULL)
return NULL;
ListNode *p1=pListHead;
ListNode *p2=pListHead;
while(k--)
{
if(p1==NULL)
return NULL;
p1=p1->next;
}
while(p1!=NULL)
{
p1=p1->next;
p2=p2->next;
}
return p2;
}
};
(7)JZ15 反转链表
反转链表,很重要,要掌握。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode*node;
ListNode*newHead=NULL;
while(pHead!=NULL)
{
node=pHead;
pHead=pHead->next;
node->next=newHead;
newHead=node;
}
return newHead;
}
};
(8)JZ16 合并两个排序链表(之后再写一遍)
这个之后还要回过来在写一遍,感觉还是没有捋的十分清楚。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
ListNode* head;
ListNode* tail;
if(pHead2==NULL)
return pHead1;
else if(pHead1==NULL)
return pHead2;
if(pHead1->val<=pHead2->val)
{
head=pHead1;
pHead1=pHead1->next;
}
else
{
head=pHead2;
pHead2=pHead2->next;
}
tail=head;
while(pHead1&&pHead2)
{
if(pHead1->val<=pHead2->val)
{
tail->next=pHead1;
pHead1=pHead1->next;
}
else
{
tail->next=pHead2;
pHead2=pHead2->next;
}
tail=tail->next;
}
if(pHead2)
{
tail->next=pHead2;
}
else if(pHead1)
{
tail->next=pHead1;
}
return head;
}
};
(9)JZ17 树的子结构
也是用的递归的思想,似乎剑指中很多树的题目都用了递归。以前递归的题目不是特别熟练,现在做多了好像好一些了。递归要考虑好边界。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
{
//空树不是任何树的子树,空树没有子树,这是第一个出口
if(pRoot2==NULL||pRoot1==NULL)
return false;
//isSubtree(pRoot1,pRoot2)表示以pRoot1作为根节点找到子结构, HasSubtree(pRoot1->left,pRoot2)表示从pRoot1的左子树找子结构
return isSubtree(pRoot1,pRoot2)||HasSubtree(pRoot1->left,pRoot2)||HasSubtree(pRoot1->right,pRoot2);
}
bool isSubtree(TreeNode *root1,TreeNode *root2)
{
//root2为NULL的时候表示root2已经全部遍历到,找到了子结构,第二个出口
if(root2==NULL)
return true;
//root1已经为NULL但是root2还不是NULL。说明root1已经全部遍历完都没有找到子结构root2,第三个出口
if(root1==NULL)
return false;
//如果root1和root2两个结点相同,再看看root1下面的每一个结点是否对应上了root2,第三个出口
if(root1->val==root2->val)
{
return isSubtree(root1->left,root2->left)&&isSubtree(root1->right,root2->right);
}
//最后一个出口,如果root1和root2此时的两个结点的值已经不相等了,就说明这次递归没有找到
return false;
}
};
(8)JZ18 二叉树的镜像
这里也是递归的交换结点的左右子树。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if(pRoot==NULL)
return ;
TreeNode *p;
p=pRoot->left;
pRoot->left=pRoot->right;
pRoot->right=p;
Mirror(pRoot->left);
Mirror(pRoot->right);
}
};
(9)JZ23 二叉搜索树的后序遍历序列
这里其实跟通过后序遍历序列和中序遍历序列构建二叉树差不多吧。二叉搜索树就默认告诉我们中序遍历序列了。
class Solution {
public:
bool flag=true;
bool VerifySquenceOfBST(vector<int> sequence) {
if(sequence.empty())
return false;
vector<int>insequence(sequence);
sort(insequence.begin(),insequence.end());
traverse(0,sequence.size()-1,0,insequence.size()-1,sequence,insequence);
return flag;
}
void traverse(int pb,int pe,int ib,int ie,vector<int>sequence,vector<int>insequence)
{
if(pb>pe)
return ;
int index=-1;
for(int i=ib;i<=ie;i++)
{
if(insequence[i]==sequence[pe])
index=i;
}
if(index==-1)
flag=false;
if(index!=-1)
{
traverse(pb,pb+index-ib-1,ib,index-1,sequence,insequence);
traverse(pb+index-ib,pe-1,index+1,ie,sequence,insequence);
}
}
};
(10)JZ26 二叉搜索树和双向链表
下面是我通过的代码,之前去网上找这个题目的题解,看别人的代码,指针看的我晕头转向。后来决定自己思考,自己写一份代码。这份代码的思路简而言之,就是通过引入stack对二叉搜索树进行非递归的中序遍历。每次都从stack中弹出当前的结点thisNode,跟上一次弹出来的结点lastNode进行指针的关联,也就是这两句:thisNode->left=lastNode; lastNode->right=thisNode;周而复始,直到全部遍历成功,并且stack中的结点全部弹出,结束。尤其要注意双向链表的头结点和尾结点,头结点只有这一句thisNode->left=lastNode;尾结点要注意把它的右指针right赋为NULL,也就是这一句thisNode->right=NULL;
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(pRootOfTree==NULL)
return NULL;
stack<TreeNode*>tree;
TreeNode *lastNode=NULL;
TreeNode *thisNode;
TreeNode *rightNode;
TreeNode *rootNode;
TreeNode *root=pRootOfTree;
while(root!=NULL)
{
tree.push(root);
if(root!=NULL&&root->left==NULL)
rootNode=root;
root=root->left;
}
while(!tree.empty())
{
thisNode=tree.top();
tree.pop();
if(lastNode==NULL)
thisNode->left=lastNode;
else if(lastNode!=NULL)
{
thisNode->left=lastNode;
lastNode->right=thisNode;
}
rightNode=thisNode->right;
if(rightNode!=NULL)
{
while(rightNode!=NULL)
{
tree.push(rightNode);
rightNode=rightNode->left;
}
}
lastNode=thisNode;
}
thisNode->right=NULL;
return rootNode;
}
};
(11)JZ27 字符串的排列
其实就是全排列?这个解法是网上通用的解法。其实就是递归的交换字符。
class Solution {
public:
vector<string> Permutation(string str) {
vector<string>result;
result.clear();
if(str=="")
return result;
sort(str.begin(),str.end());
int length=str.length();
permu(0,length,str,result);
return result;
}
void permu(int index,int length,string str,vector<string>&result)
{
if(index==length)
{
result.push_back(str);
return ;
}
for(int i=index;i<length;i++)
{
if(i!=index&&str[i]==str[index])
continue;
swap(str[i],str[index]);
permu(index+1,length,str,result);
}
}
};
(12)JZ28 数组中出现次数超过一半的数字
这个题目考察vector吧,要注意题目没有说清楚数组的长度怎么计算,所以判断是否超过数组长度的一半这里可能会出问题。
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
if(numbers.empty())
return 0;
int length=numbers.size();
int count=0;
sort(numbers.begin(),numbers.end());
for(int i=0;i<length;i++)
{
if(i==0)
{
count++;
continue;
}
if(numbers[i]==numbers[i-1])
count++;
if(numbers[i]!=numbers[i-1])
{
if(count>floor(length/2.0))
return numbers[i-1];
count=1;
}
}
if(count>floor(length/2.0))
return numbers[length-1];
return 0;
}
};
(13)JZ30 连续子数组的最大和
动态规划的很经典的题目了
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
int dp[array.size()+10];
int ans;
dp[0]=array[0];
for(int i=1;i<array.size();i++)
{
dp[i]=max(dp[i-1]+array[i],array[i]);
}
ans=*max_element(dp,dp+array.size());
return ans;
}
};
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode *head2;
while(pHead1!=NULL)
{
head2=pHead2;
while(head2!=NULL)
{
if(pHead1==head2)
return head2;
head2=head2->next;
}
pHead1=pHead1->next;
}
return NULL;
}
};
(15)JZ38 二叉树的深度
也是树里面很基础但是也很重要的一个题目了。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
int length=0;
int TreeDepth(TreeNode* pRoot)
{
if(pRoot==NULL)
return 0;
dfs(pRoot,1);
return length;
}
void dfs(TreeNode *root,int dep)
{
if(root->left==NULL&&root->right==NULL)
{
if(dep>length)
length=dep;
return ;
}
if(root->left)
dfs(root->left,dep+1);
if(root->right)
dfs(root->right,dep+1);
}
};
(16)JZ39 平衡二叉树
还是递归的判断,递归真的是广泛的应用于树中。
class Solution {
public:
int flag=0;
bool IsBalanced_Solution(TreeNode* pRoot) {
if(pRoot==NULL)
return true;
isBa(pRoot,1);
if(flag==0)
return true;
if(flag==1)
return false;
}
int isBa(TreeNode* p,int depth)
{
int ldep;
int rdep;
if(p->left)
ldep=isBa(p->left,depth+1);
else
ldep=depth;
if(p->right)
rdep=isBa(p->right,depth+1);
else
rdep=depth;
if(abs(ldep-rdep)>=2)
flag=1;
return max(ldep, rdep);
}
};
(17)JZ55 链表在环的入口结点
这里也是网上很通用的解法。两个指针一个每次走一步,一个每次走两步。两个指针相遇后,让走的快的指针重新到达链表的初始位置,这时每次是走一步了。最后两个指针会相遇于环的入口。
有具体的数学推导过程,可以去网上搜。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode *fast=pHead;
ListNode *low=pHead;
if(pHead==NULL)
return NULL;
while(fast->next!=NULL&&low->next!=NULL&&fast!=NULL)
{
fast=fast->next->next;
low=low->next;
if(fast==low)
{
fast=pHead;
while(fast!=low)
{
fast=fast->next;
low=low->next;
}
return low;
}
}
return NULL;
}
};
(18)JZ56 删除链表中重复的结点
这里我是在循环中,判断是否是重复结点,然后进行删除。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
vector<int>del;
int flag=0;
int delFir=0;
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead==NULL)
return NULL;
ListNode *head=pHead;
ListNode *LastNode=NULL;
while(pHead!=NULL)
{
if(pHead->next==NULL)
break;
while(pHead->val==pHead->next->val)
{
pHead->next=pHead->next->next;
flag=1;
if(pHead->next==NULL)
break;
}
if(flag==0)
LastNode=pHead;
if(flag==1)
{
if(pHead==head)
{
delFir=1;
LastNode=pHead;
}
if(pHead!=head)
{
LastNode->next=pHead->next;
}
flag=0;
}
pHead=pHead->next;
}
if(delFir==1)
head=head->next;
return head;
}
};
(19)JZ57 二叉树的下一个结点
这里需要考虑到三种情况,是父节点的left结点,是父节点的right结点并且有子节点,是父节点的right结点并且没有子节点。知道这三种情况对应怎么解决就行。
/*
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* GetNext(TreeLinkNode* pNode)
{
if(pNode==NULL)
return NULL;
if(pNode->right!=NULL)
{
if(pNode->right->left==NULL)
return pNode->right;
else
{
pNode=pNode->right;
while(pNode->left!=NULL)
{
pNode=pNode->left;
}
return pNode;
}
}
else
{
if(pNode->next==NULL)
return NULL;
if(pNode->next->left==pNode)
{
return pNode->next;
}
else
{
while(pNode!=pNode->next->left)
{
pNode=pNode->next;
if(pNode->next==NULL)
break;
}
if(pNode->next==NULL)
return NULL;
return pNode->next;
}
}
}
};
(20)按之字形顺序打印二叉树
这个题目就是要以层序遍历作为基础,知道中间要反转输出就行。
/*
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) {
vector<int>perlayer;
vector<vector<int> > ans;
if(pRoot==NULL)
return ans;
vector<int>layernum;
vector<int>nodelist;
int layer;
queue<TreeNode*>mid;
mid.push(pRoot);
layernum.push_back(1);
while(!mid.empty())
{
nodelist.push_back(mid.front()->val);
layer=layernum[nodelist.size()-1]+1;
if(mid.front()->left!=NULL)
{
mid.push(mid.front()->left);
layernum.push_back(layer);
}
if(mid.front()->right!=NULL)
{
mid.push(mid.front()->right);
layernum.push_back(layer);
}
mid.pop();
}
perlayer.push_back(nodelist[0]);
for(int i=1;i<nodelist.size();i++)
{
if(layernum[i]==layernum[i-1])
perlayer.push_back(nodelist[i]);
else
{
if(layernum[i-1]%2)
ans.push_back(perlayer);
else
{
reverse(perlayer.begin(),perlayer.end());
ans.push_back(perlayer);
}
perlayer.clear();
perlayer.push_back(nodelist[i]);
}
}
if(layernum[nodelist.size()-1]%2==0)
reverse(perlayer.begin(),perlayer.end());
ans.push_back(perlayer);
return ans;
}
};
(21)JZ60 把二叉树打印成多行
层序遍历,较为基础,也很重要。
/*
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) {
vector<vector<int>> ans;
queue<TreeNode*> q;
vector<int>mid;
vector<int>flag;
int count=1;
if(pRoot==NULL)
return ans;
q.push(pRoot);
flag.push_back(count);
int midd;
while(!q.empty())
{
mid.push_back(q.front()->val);
midd=flag[mid.size()-1]+1;
if(q.front()->left!=NULL)
{
q.push(q.front()->left);
flag.push_back(midd);
}
if(q.front()->right!=NULL)
{
q.push(q.front()->right);
flag.push_back(midd);
}
q.pop();
}
vector<int>per;
for(int i=0;i<flag.size();i++)
{
if(i==0)
per.push_back(mid[i]);
else
{
if(flag[i]==flag[i-1])
per.push_back(mid[i]);
else
{
ans.push_back(per);
per.clear();
per.push_back(mid[i]);
}
}
}
ans.push_back(per);
return ans;
}
};
(22)JZ62 二叉搜索树的第k个结点
较为基础,上面倒数第k个结点都做了,这个应该没问题。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
int count=0;
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if(pRoot==NULL)
return NULL;
if(pRoot!=NULL)
{
TreeNode *left=KthNode(pRoot->left, k);
if(left!=NULL)
return left;
count++;
if(count==k)
return pRoot;
TreeNode *right=KthNode(pRoot->right,k);
if(right!=NULL)
return right;
}
return NULL;
}
};
(23)剪绳子
又是动态规划,也是超级经典的题目呀。
class Solution {
public:
int cutRope(int number) {
int max1,max2;
int num;
int dp[100];
for(int i=0;i<100;i++)
dp[i]=1;
for(int i=2;i<=number;i++)
{
for(int j=1;j<i;j++)
{
max1=max(dp[j]*(i-j),dp[j]*dp[i-j]);
max2=max(j*(i-j),j*dp[i-j]);
num=max(max1,max2);
if(num>dp[i])
dp[i]=num;
};
}
return dp[number];
}
};