部分文字代碼copy模仿,如有雷同,請勿介意小白記錄敲代碼的過程。
1.鏈表中倒數第k個結點
輸入一個鏈表,輸出該鏈表中倒數第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||k==0)return NULL;
ListNode* phead=pListHead,*ptail=pListHead;;
for(int i=1;i<k;++i){
if(phead->next!=NULL){
phead=phead->next;
}else{
return NULL;
}
}
while(phead->next!=NULL){
phead=phead->next;
ptail=ptail->next;
}
return ptail;
}
};
2.訪問單個節點的刪除
實現一個算法,刪除單向鏈表中間的某個結點,假定你只能訪問該結點。
給定待刪除的節點,請執行刪除操作,若該節點爲尾節點,返回false,否則返回true
思路:不刪這個節點了,把下個節點值copy過來,然後刪除下個節點
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Remove {
public:
bool removeNode(ListNode* pNode) {
// write code here
if(pNode==NULL)return NULL;
if(pNode->next==NULL){
delete pNode;
return false;
}else{
ListNode* newnode;
newnode=pNode->next;
pNode->val=newnode->val;
pNode->next=newnode->next;
delete newnode;
return true;
}
}
};
3.鏈表分割
編寫代碼,以給定值x爲基準將鏈表分割成兩部分,所有小於x的結點排在大於或等於x的結點之前
給定一個鏈表的頭指針 ListNode* pHead,請返回重新排列後的鏈表的頭指針。注意:分割以後保持原來的數據順序不變。
思路:創建小數鏈表和大數鏈表,最後完成後將兩鏈表連接,注意頭結點也有值,需要進行比較。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
ListNode* small=new ListNode(0);
ListNode* large=new ListNode(0);
ListNode* smallhead=small;
ListNode* largehead=large;
while(pHead){
if(pHead->val<x){
small->next=pHead;
small=small->next;
}else{
large->next=pHead;
large=large->next;
}
pHead=pHead->next;
}
large->next=NULL;
small->next=largehead->next;
return smallhead->next;
}
};
4.鏈式A+B
有兩個用鏈表表示的整數,每個結點包含一個數位。這些數位是反向存放的,也就是個位排在鏈表的首部。編寫函數對這兩個整數求和,並用鏈表形式返回結果。
給定兩個鏈表ListNode* A,ListNode* B,請返回A+B的結果(ListNode*)。
測試樣例:
{1,2,3},{3,2,1}
返回:{4,4,4}
思路:對應位相加,注意是否有進位,最後返回鏈表長的那個做爲結果。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Plus {
public:
ListNode* plusAB(ListNode* a, ListNode* b) {
// write code here
ListNode* newlist=new ListNode(0);
ListNode* p=newlist;
ListNode* node;
int c=0;
int sum;
int val1,val2;
while(a!=NULL || b!=NULL || c!=0){
val1 = (a == NULL ? 0 : a->val);
val2 = (b == NULL ? 0 : b->val);
sum = val1 + val2 + c;
c = sum / 10;
node = new ListNode(sum % 10);
p->next=node;
p=node;
a=(a == NULL ? NULL : a->next);
b=(b == NULL ? NULL : b->next);
}
return newlist->next;
}
};
5.迴文鏈表
請編寫一個函數,檢查鏈表是否爲迴文。
給定一個鏈表ListNode* pHead,請返回一個bool,代表鏈表是否爲迴文。
測試樣例:
{1,2,3,2,1}
返回:true
{1,2,3,2,3}
返回:false
思路:
1>反轉鏈表:可以將原始鏈表反轉,判斷反轉以後的鏈表與原始鏈表是否完全一致,如果一致便返回true,如果不一致則返回false。反轉鏈表需要額外的存儲空間,不是特別優秀的方法。
2>棧實現:我們可以想到從中間節點向兩側開始比較,如果全部相同,則返回true,否則返回false,因爲無法獲得一個節點的前一個節點,這個時候我們可以想到用棧實現,先將鏈表前半部分的元素分別壓入堆棧,然後在遍歷後半部分元素的時候同時和棧頂元素進行比較,如果全部相等則返回true,否則返回false。
特別注意:因爲我們不知道鏈表的的長度,可以通過快慢指針(一個指針每次移動兩個,一個指針每次移動一個)來找到中間元素,這樣整體只需要遍歷鏈表一次,所需要的棧空間縮小爲方法1的一半。
3>遞歸:遞歸方法分爲尾部遞歸和首部遞歸,還有中間遞歸,一般的尾部遞歸都可以用循環來實現,對於我們這道題目,遞歸的時候無法比較第一個元素和最後一個元素,即使知道最後一個元素,也無法獲得最後一個元素的前一個元素。所以我們選擇首部遞歸,先遞歸直到中間的元素,然後比較中間的元素,把比較結果返回,同時保存後半部分下一個要比較的元素(用引用傳遞可以,用二級指針也可以),遞歸返回後,如果是true,則繼續比較,如果是false,則直接返回false。
方法一:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Palindrome {
public:
bool isPalindrome(ListNode* pHead) {
// write code here
if (pHead == NULL)return false;
ListNode* reverselist=new ListNode(0);
ListNode* pa=pHead;
ListNode* pb;
reverselist->next=NULL;
while(pa!=NULL){
pb=new ListNode(pa->val);
pb->next=reverselist->next;
reverselist->next=pb;
pa=pa->next;
}
pa=pHead;
pb=reverselist->next;
while(pa!=NULL&&pb!=NULL){
if(pa->val==pb->val){
pa=pa->next;
pb=pb->next;
}else{
return false;
}
}
return true;
}
};
方法二:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Palindrome {
public:
bool isPalindrome(ListNode* pHead) {
// write code here
stack<int> s;
if(pHead==NULL)return false;
ListNode* p=pHead;
ListNode* q=pHead;
s.push(p->val);
while(q->next!=NULL&&q->next->next!=NULL){
p=p->next;
s.push(p->val);
q=q->next->next;
}
if(q->next==NULL){
s.pop();
}
while(p->next!=NULL){
p=p->next;
if(p->val==s.top()){
s.pop();
}
else{
return false;
}
}
return true;
}
};
方法三:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Palindrome {
public:
bool isPalindrome(ListNode* pHead) {
// write code here
ListNode *tail=pHead;
int length=0;
while(tail!=NULL){
length++;
tail=tail->next;
}
return ispd(pHead,&tail,length);
}
bool ispd(ListNode* pHead,ListNode** tail,int length){
if(length==0||pHead==NULL){
return true;
}
if(length==1){
*tail=pHead->next;
return true;
}
if(length==2){
if(pHead->val==pHead->next->val){
*tail=pHead->next->next;
return true;
}else{
return false;
}
}
bool flag=ispd(pHead->next,tail,length-2);
if(flag==false)return false;
ListNode* tail1=*tail;
if(pHead->val==tail1->val){
*tail=tail1->next;
return true;
}else{
return false;
}
}
};