反转链表
反转链表有两种方法,分别是迭代法和递归法。
迭代法
有两种思路,一种是把头结点的下一个节点一次移动到第一个,直到头结点变成最后一个;第二种是依次把第一个节点移动到尾结点的后面,直到尾结点变成第一个。
递归法
假设除头节点以外的所有节点都已反转,把头结点以后的链表看做一个整体,则需要做的操作就是把头结点移动到它的后面。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL||head->next==NULL)
return head;
ListNode *newhead=reverseList(head->next);
head->next->next=head;
head->next=NULL;
return newhead;
}
};
移除指定元素
迭代法
用差距为一的前后两个指针同时行进,前面一个指针的节点数据是如果等于指定数据则删除。
递归法
首先假设除头结点外的链表中的指定元素都删除了,然后只要保证头结点的数据不等于指定,如果等于则删除头结点。
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
if(head==NULL)
return NULL;
head->next=removeElements(head->next,val);
if(head->val==val)
return head->next;
else
return head;
}
};
奇偶链表
问题描述:给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。
这个问题与反转链表有点类似,先找到链表的尾结点,其次把头结点的下一个节点移到尾结点的后面,最后头尾节点各后移一位,循环次数为链表长度n/2。
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(head==NULL||head->next==NULL||head->next->next==NULL)
return head;
ListNode *tail,*a,*b;
tail=head;a=head;
int i=1;
while(tail->next!=NULL)
{
tail=tail->next;
i++;
}
for(int j=0;j<i/2;j++)
{
b=a->next;
a->next=b->next;
tail->next=b;
b->next=NULL;
tail=b;
a=a->next;
}
return head;
}
};
判断是否为回文链表
迭代法
迭代法的思路是先把链表的前一半反转,然后用两个指针分别遍历前后一半。这个做法还需要注意链表长度的奇偶,相对比较复杂。
class Solution {
public:
bool isPalindrome(ListNode* head) {
if(head==nullptr||head->next==nullptr)
return true;
ListNode *fast,*slow,*head1,*head2;
fast=head->next;slow=head;
bool isodd=false;
while(fast->next!=nullptr)
{
fast=fast->next;
if(fast->next==nullptr)
{isodd=true; break;}
fast=fast->next;
slow=slow->next;
}
if(slow==head)
{
if(slow->val==fast->val)
return true;
else
return false;
}
if(isodd)
head2=slow->next->next;
else
head2=slow->next;//找到链表的一半
ListNode *a,*b;
a=head;
while(a!=slow)
{
b=a->next;
a->next=slow->next;
slow->next=a;
a=b;
}//前一半反转
head1=slow;
while(head2!=nullptr)
{
if(head1->val!=head2->val)
return false;
head1=head1->next;
head2=head2->next;
}
return true;
}
};
递归法
- 设置一个全局变量,用于保存头节点的引用。
- 递归到最底层,然后返回的时候,和头节点同时比较(头节点从前往后,他从后往前)
class Solution {
ListNode first;
public boolean isPalindrome(ListNode head) {
// 使用递归的方法
first = head;
return helper(head);
}
public boolean helper(ListNode last){
if(last != null){
// 一直递归下去
if(!helper(last.next)) return false;
// 出递归的时候,正好是从后往前
if(last.val != first.val) return false;
first = first.next;
}
return true;
}
}
递归法非常精妙地利用了递归传递的条件,即链表为空或者这一层的头尾元素相同,把这个条件变成bool变量,通过两个判断语句完成了这个过程。