算法-链表

算法-链表

 

    云想衣裳花想容,春风拂槛露华浓。

 

简介:算法-链表

一、从尾到头打印链表

1、题目描述

输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。
输入:
{1,2,3}
返回值:
[3,2,1]

2、解题思路

使用递归

要逆序打印链表 1->2->3(3,2,1),可以先逆序打印链表 2->3(3,2),最后再打印第一个节点 1。而链表 2->3 可以看成一个新的链表,要逆序打印该链表可以继续使用求解函数,也就是在求解函数中调用自己,这就是递归函数。

算法-链表
 1 import java.util.*;
 2 public class Solution {
 3     public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
 4         ArrayList<Integer> ret = new ArrayList<>();
 5         if (listNode != null) {
 6             // 递归
 7             ret.addAll(printListFromTailToHead(listNode.next));
 8             ret.add(listNode.val);
 9         }
10         return ret;
11     }
12 }
View Code

算法-链表

二、删除链表中重复的节点

1、题目描述

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

输入:
{1,2,3,3,4,4,5}
返回值:
{1,2,5}

2、解题思路

借助辅助头结点,可避免单独讨论头结点的情况。设置两个结点 pre 和 cur,当 cur 和 cur.next 值相等,cur 一直向前走,直到不等退出循环,这时候 cur 指的值还是重复值,调整 cur 和 pre 的指针再次判断。

算法-链表
 1 /*
 2 删除链表中重复的结点
 3 */
 4 public class Solution {
 5     public ListNode deleteDuplication(ListNode pHead) {
 6         /*
 7         构建辅助头结点
 8         对于链表而言,不保存的意思也就是跳过这一结点next指向下一个结点
 9          */      
10         ListNode head=new ListNode(-1);
11         head.next=pHead;
12         ListNode saveHead=head;//保存下来的结点
13         ListNode currentNode=pHead;
14         while(currentNode!=null){
15             if(currentNode.next!=null && currentNode.val==currentNode.next.val) {//有重复了,跳过
16                 while (currentNode.next != null && currentNode.val == currentNode.next.val) {
17                     currentNode = currentNode.next;//跳过这些相同结点
18                 }
19                 currentNode=currentNode.next;//有重复,一个都不保存
20                 saveHead.next=currentNode;//保存
21             }
22             else {
23                 //这里是没重复的
24                 saveHead=currentNode;
25                 currentNode=currentNode.next;
26             }
27         }
28         return head.next;
29     }
30 }
View Code

算法-链表

三、链表中倒数第K 个结点

1、题目描述

输入一个链表,输出一个链表,该输出链表包含原链表中从倒数第k 个结点至尾节点的全部节点。如果该链表长度小于k,请返回一个长度为 0 的链表。
输入:
{1,2,3,4,5},1 
返回值:
{5}

2、解题思路

在链表中:倒数的+顺数的长度等于链表总长度,所以可以设置两个指针,一个先走K 步,剩下的到链表的末尾要走的步数就是倒数第k个节点,需要从头开始走的步数。

算法-链表
 1 import java.util.*;
 2 
 3 /*
 4  链表中倒数最后k 个结点
 5  */
 6 public class Solution {
 7     public ListNode FindKthToTail (ListNode pHead, int k) {       
 8         ListNode first = pHead;
 9         for(int i = 0; i < k; i++){
10             if(first == null){
11                 return first;
12             }
13             first = first.next;
14         }
15         ListNode last = pHead;
16         while(first != null){
17             first = first.next;
18             last = last.next;
19         }
20         return last;
21     }
22 }
View Code

算法-链表

四、链表中环的入口结点

1、题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
输入:
{1,2},{3,4,5}
返回值:
3
说明:
返回环形链表入口节点,我们后台会打印该环形链表入口节点,即3 

2、解题思路

使用双指针,一个快指针 fast 每次移动两个节点,一个慢指针 slow 每次移动一个节点。因为存在环,所以两个指针必定相遇在环中的某个节点上。

假设环入口节点为 y1,相遇所在节点为 z1。

假设快指针 fast 在圈内绕了 N 圈,则总路径长度为 x+Ny+(N-1)z。z 为 (N-1) 倍是因为快慢指针最后已经在 z1 节点相遇了,后面就不需要再走了。

而慢指针 slow 总路径长度为 x+y。

因为快指针是慢指针的两倍,因此 x+Ny+(N-1)z = 2(x+y)。

我们要找的是环入口节点 y1,也可以看成寻找长度 x 的值,因此我们先将上面的等值分解为和 x 有关:x=(N-2)y+(N-1)z。

上面的等值没有很强的规律,但是我们可以发现 y+z 就是圆环的总长度,因此我们将上面的等式再分解:x=(N-2)(y+z)+z。这个等式左边是从起点x1 到环入口节点 y1 的长度,而右边是在圆环中走过 (N-2) 圈,再从相遇点 z1 再走过长度为 z 的长度。此时我们可以发现如果让两个指针同时从起点 x1 和相遇点 z1 开始,每次只走过一个距离,那么最后他们会在环入口节点相遇。

算法-链表

算法-链表
 1 /*
 2 链表中环的入口结点
 3 */
 4 public class Solution {
 5 
 6     public ListNode EntryNodeOfLoop(ListNode pHead) {
 7         if(pHead == null || pHead.next == null){
 8             return null;
 9         }
10         ListNode slow = pHead;
11         ListNode fast = pHead;
12         do{
13             fast = fast.next.next;
14             slow = slow.next;
15         }while(slow != fast);
16         fast = pHead;
17         while(slow != fast){
18             slow = slow.next;
19             fast = fast.next;
20         }
21         return slow;       
22     }
23 }
View Code

算法-链表

五、链表中环的入口结点

1、题目描述

输入一个链表,反转链表后,输出新链表的表头。
输入:
{1,2,3}
返回值:
{3,2,1}

2、解题思路

递归

算法-链表
 1 /*
 2 反转链表
 3 */
 4 public class Solution {
 5     public ListNode ReverseList(ListNode head) {
 6         if(head == null || head.next == null){
 7             return head;
 8         }
 9         ListNode next = head.next;      
10         // 递归
11         ListNode newHead = ReverseList(next);
12         next.next = head;
13         head.next = null;
14         return newHead;
15     }
16 }
View Code

算法-链表

 

 

 

 

云想衣裳花想容

    春风拂槛露华浓

 

 

 

 

 

上一篇:信息学奥赛C++语言:时间转换


下一篇:贪婪最佳优先算法之美