标签:int 头结点 ota new 输出 规则 boolean 复杂 快慢指针法
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
// 典型的前后双指针
if(pHead == null || pHead.next == null){
return pHead;
}
ListNode fast = pHead.next;
ListNode slow = new ListNode(0);
boolean needHead = true;
if(pHead.val == fast.val){
slow = pHead;
needHead = false;
}else{
slow.next = pHead;
}
while(fast != null){
if(fast.val != slow.next.val){
fast = fast.next;
slow = slow.next;
continue;
}
while(fast.next != null && fast.val == slow.next.val){
fast = fast.next;
}
if(fast.val == slow.next.val){
slow.next = null;
break;
}
slow.next = fast;
fast = fast.next;
}
if(needHead){
return pHead;
}else if(pHead.next == null){
return null;
}
return pHead.next;
}
}
public ListNode FindKthToTail(ListNode head, int k) {
// 考虑k的值有哪些情况
// k值可能为负值,0,或者超过链表长度的值,当出现这些情况的时候,要进行相应的提示
//快慢指针法
if(head == null || k<=0){
return null;
}
ListNode fast = head;
for(int i = 0; i < k-1; i++){
if(fast.next != null){
fast = fast.next;
}else{
return null;
}
}
ListNode slow = head;
while(fast.next != null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
Java语言的话有两种解法:
第一步,检测链表中是否真的存在环。
由于链表中存在环,快指针在进入环后会不断循环,因此慢指针一定会追上快指针。反过来也表示,如果慢指针追上快指针了,即表示链表中存在环。
第二步,找到环的入口。
假设环的长度为n,我们可以使用上文间隔一定距离的双指针法进行求解。定义前指针在链表开头,定义后指针在前指针的n个节点后,两指针同时后移,当两个指针相同时,即为环的入口。
第三步,为了得到环的入口,我们需要知道环的长度。
同理可以使用间隔一定距离的双指针法。由第一步可得,在环中已经有两个指针,可以保持一个指针不动,另一个指针向前移动,同时计数,当两个指针再一次重合时,即可得到环的长度。
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null){
return null;
}
// 1.判断链表中有环
ListNode l=pHead,r=pHead;
boolean flag = false;
while(r != null && r.next!=null){
l=l.next;
r=r.next.next;
if(l==r){
flag=true;
break;
}
}
if(!flag){
return null;
}else{
// 2.得到环中节点的数目
int n=1;
r=r.next;
while(l!=r){
r=r.next;
n++;
}
// 3.找到环中的入口节点
l=r=pHead;
for(int i=0;i<n;i++){
r=r.next;
}
while(l!=r){
l=l.next;
r=r.next;
}
return l;
}
}
Java中有两种解法:
我们可以从前到后遍历链表,遍历的过程中可以调转前后节点的指向顺序,但是需要注意的是,反转完前后节点的指向顺序后,后节点后面的节点就不能拼接当前指针了,因此我们还需要额外添加一个结点指向后节点的后节点。
public ListNode ReverseList(ListNode head) {
// 判断链表为空或长度为1的情况
if(head == null || head.next == null){
return head;
}
ListNode pre = null; // 当前节点的前一个节点
ListNode next = null; // 当前节点的下一个节点
while(head != null){
next = head.next; // 记录当前节点的下一个节点位置;
head.next = pre; // 让当前节点指向前一个节点位置,完成反转
pre = head; // pre 往右走
head = next;// 当前节点往右继续走
}
return pre;
}
简单的合并链表,可以以其中一个链表为主体,将另一个链表逐渐加进来。需要注意的是初始指针要设置为null,并指向两个链表的首部。
public ListNode Merge(ListNode list1,ListNode list2) {
//创建一个头结点会更方便
if(list1 == null){
return list2;
}else if(list2 == null){
return list1;
}
ListNode h = new ListNode(Integer.MIN_VALUE);
ListNode r = h;
while(list1 != null && list2 != null){
if(list1.val < list2.val){
r.next = list1;
list1 = list1.next;
}else{
r.next = list2;
list2 = list2.next;
}
r = r.next;
}
if(list1 != null) r.next = list1;
if(list2 != null) r.next = list2;
return h.next;
}
这道题类似于树中的寻找两节点的最小公共祖先。因此可以类比树的解法。
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
// 类似于查找树的最早祖先,使用快速幂来算
// 第一步是让两个链表的指针调整到同一水平线
int count1 = 0;
int count2 = 0;
ListNode p1 = pHead1;
ListNode p2 = pHead2;
while(p1 != null){
p1 = p1.next;
count1++;
}
while(p2 != null){
p2 = p2.next;
count2++;
}
while(count1 != count2){
if(count1 > count2){
pHead1 = pHead1.next;
count1--;
}else{
pHead2 = pHead2.next;
count2--;
}
}
while(pHead1 != pHead2){
pHead1 = pHead1.next;
pHead2 = pHead2.next;
}
return pHead1;
}
标签:int 头结点 ota new 输出 规则 boolean 复杂 快慢指针法
原文地址:https://www.cnblogs.com/Water2Wine/p/12416603.html