输入一个链表,输出该链表中倒数第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;inext!=NULL){
phead=phead->next;
}else{
return NULL;
}
}
while(phead->next!=NULL){
phead=phead->next;
ptail=ptail->next;
}
return ptail;
}
};
实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。
给定待删除的节点,请执行删除操作,若该节点为尾节点,返回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;
}
}
};
编写代码,以给定值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->valnext=pHead;
small=small->next;
}else{
large->next=pHead;
large=large->next;
}
pHead=pHead->next;
}
large->next=NULL;
small->next=largehead->next;
return smallhead->next;
}
};
有两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表的首部。编写函数对这两个整数求和,并用链表形式返回结果。
给定两个链表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;
}
};
请编写一个函数,检查链表是否为回文。
给定一个链表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 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;
}
}
};