菜鸡,立下一个小目标,及时更新and总结。
1.变态跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
注意:一次可以跳n,不是只能跳1、2。
可以推出:
class Solution {
public:
int jumpFloorII(int number) {
int dp[number+1];
dp[1]=1;
dp[2]=2;
for(int i=3;i<=number;i++){
dp[i]=2*dp[i-1];
}
return dp[number];
}
};
2.链表中倒数第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 || k<= 0)return nullptr;
ListNode *f=pListHead,*l=pListHead;
while(k--){
if(f)f=f->next;
else return nullptr;
}
while(f){
f=f->next;
l=l->next;
}
return l;
}
};
3.翻转链表
我永远记得我第一次面试就栽在翻转链表,都是泪。
双指针,pre指向头,cur指向Null,pre->next=cur;cur 与pre同时向前移动。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode *pre=pHead,*cur=nullptr,*temp=nullptr;
while(pre){
temp=pre->next;
pre->next=cur;
cur=pre;
pre=temp;
}
return cur;
}
};
4.合并两个排序的链表
A.迭代方法:
new一个新的ListNode,因为最后条件是只要有一个链表遍历到了最后就退出,所以不要忘记最后将没有遍历完的链表放在新链表中。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2){
if(!pHead1 && !pHead2)return nullptr;
ListNode* dummy=new ListNode(-1);
ListNode* cur=dummy;
while(pHead1 && pHead2){
if(pHead1->val < pHead2->val){
cur->next=pHead1;
pHead1=pHead1->next;
}else{
cur->next=pHead2;
pHead2=pHead2->next;
}
cur=cur->next;
}
cur->next=pHead1 ? pHead1:pHead2;
return dummy->next;
}
};
B.递归
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(!pHead1)return pHead2;
if(!pHead2)return pHead1;
if(pHead1->val < pHead2->val){
pHead1->next=Merge(pHead1->next,pHead2);
return pHead1;
}else{
pHead2->next=Merge(pHead1,pHead2->next);
return pHead2;
}
}
};
5.复杂链表的复制
剑指offer,分三步:
1.复制链表,插入复制的节点后,如:A->A'->B->B';
2.random指向复制;
3.分离两个链表
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(!pHead) return NULL;
RandomListNode* p;
p=pHead;
while(p){
RandomListNode* q = new RandomListNode(p->label);
RandomListNode* temp=p->next;
p->next=q;
q->next=temp;
p=q->next;
}
p=pHead;
while(p){
p->next->random = p->random==NULL ? NULL:p->random->next;
p=p->next->next;
}
RandomListNode *res = pHead->next;
RandomListNode *tmp;
p = pHead;
while(p->next){
tmp = p->next;
p->next =tmp->next;
p = tmp;
}
return res;
}
};
6.两个链表的第一个公共结点
a+b+c = c+b+a;
/*
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;
while(p1 != p2){
p1 = p1?p1->next : pHead2;
p2 = p2?p2->next : pHead1;
}
return p2;
}
};
7.环形链表的入口
用快慢指针,快指针两步,慢指针一步,如果二者相遇,则有环。
画个图就知道,让快指针从链表头,慢指针从相遇点,都各自走一步,则再次相遇为入口。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* fast=pHead,*slow=pHead;
while(slow && fast && fast->next){
fast=fast->next->next;
slow=slow->next;
if(fast==slow)break;
}
//如果没有环,则fast或者fast->next为空
if(fast == NULL || fast->next == NULL)return NULL;
fast=pHead;
while(fast!=slow){
fast=fast->next;
slow=slow->next;
}
return fast;
}
};