一、06 旋转链表
问题描述
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
解题思路
1、闭合为环
a、将链表连成环;
b、计算新的Head位置,并将head前一个元素的next值设置为null;
c、返回新的head。
var rotateRight=function(head,k){
if(head==null||head.next==null) return head;
let cur=head;
let count=1;
while(cur.next){
cur=cur.next;
count++;
}
cur.next=head;//首尾连接形成环
k=count-k%count;//计算要移动的距离
while(k--) cur=cur.next;
head=cur.next; //head指向第len-k+q个节点,即旋转后的链表的头节点
cur.next=null;
return head;
};
2、模拟
a、首先遍历链表求出链表长度len,并找出链表的尾节点tail;
b、因为k的值可能大于链表长度len,所以计算移动距离(翻转后链表的头节点时)需要令k=k%n(长5,移6,实际移1)。再次从头节点head开始遍历,找到第len-k个节点p,那么节点1~p是链表的前len-k个节点,
p+1~len是链表的后k个节点。
c、然后将链表的后k % len个节点和前len - (k % len)个节点连接到一块即可得到翻转后的链表,即令tail.next=head;newhead=p.next;p.next=null;
d、返回新节点newhead.
具体代码如下:
var rotateRight=function(head,k){
if(head==null||head.next==null){
return head;
}
let len=1;
let tail=head;
while(tail.next){ //找到尾节点
len++;
tail=tail.next;
}
k=len-k%len;
let p=head;
while(--k) p=p.next;
tail.next=head;
let newhead=p.next;
p.next=null;
return newhead;
};
二、83 删除排序链表中的重复元素
问题描述
给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
解题思路
这个和82题类似,只是82是删除所有重复元素,但是这个题需要保留一个重复的元素。
采用类似的方法虚拟节点+双指针;
a、设置虚拟节点dummyhead,使其next指向head,方便返回结果;
b、设置指针fast=head.next,slow=head。若fast和slow指针的值相同,说明数值重复,此时需要删除fast指针所指向的节点,即slow.next=fast.next,指针fast后移一位;
c、否则,fast和slow指针分别后移一位。
var deleteDuplicates = function(head) {
if(head==null||head.next==null) return head;
let dummyhead=new ListNode(0,head);
let fast=head.next;
let slow=head;
while(fast){
if(fast.val==slow.val){
slow.next=fast.next;
}else{
slow=fast;
}
fast=fast.next;
}
return dummyhead.next;
};
三、 86 分隔链表
问题描述
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
解题思路
1、使用栈
a、设置虚拟节点dummyhead,作为新建链表的头节点,方便返回分隔后的链表;
b、令p=dummyhead来形成新链表,令指针cur=head来遍历原链表,cur.val和x做比较,小于x的节点采用尾插法直接接在新建链表p的末尾,大于x的先存入新建栈bigger中;
c、遍历结束后,令p.next=null,这是为了断开链表,防止后面存在大于x的节点未被去除;
d、采用头插法,将栈中元素弹出接在链表尾部;
e、返回dummyhead.next。
具体代码如下
var partition=function(head,x){
if(head==null||head.next==null) return head;
let bigger=[];
let dummyhead=new ListNode(0);
let p=dummyhead;
let cur=head;
while(cur){
if(cur.val<x){
p.next=cur;
}else{
bigger.push(cur.val);
}
cur=cur.next;
}
p.next=null;
while(bigger.length){
let newnode=new ListNode(bigger.pop());
newnode.next=p.next;
p.next=newnode;
}
return dummyhead;
};
2、虚拟节+双指针
a、初始化虚拟节点dmy和快慢指针fast、slow;
b、令慢指针slow水中保持指向新形成链表的最后一个小于x的节点;
c、fast从slow开始向后寻找其他小于x的节点;
i、若找到小于x的节点,则需要将该节点摘出来拼接到slow的后面,并将slow后移,始终保持slow指向新建立节点中最后一个小于x的节点;
ii、若未找到则fast指针向后迭代
d、返回dmy.next;
var partition=function(head,x){
let dmy=new ListNode(-1,head);
let slow=dmy;
let fast=null;
while(slow!=null&&slow.next!=null){
if(slow.next.val>=x) break;
slow=slow.next;
}
fast=slow;
while(fast!==null&&fast.next!==null){
if(fast.next.val<x){
let tmp=fast.next;
fast.next=fast.next.next;
tmp.next=slow.next;
slow.next=tmp;
slow=slow.next;
}else{
fast=fast.next;
}
}
return dmy.next;
};