剑指offer之链表

总结:链表增删改查,重点找到相应的节点,以及特殊情况的处理(链表为空,一个节点情况,尾节点情况)

  1 package jzoffer;
  2 
  3 import java.util.ArrayList;
  4 import java.util.Scanner;
  5 import java.util.Stack;
  6 
  7 public class LinkList
  8 {
  9     Node head = new Node();
 10     public void addNode(int data){//从末尾添加元素
 11         Node newNode = new Node(data),current = head;
 12         if(head.next ==null) {
 13             head = new Node();
 14             head.next = newNode;
 15         }
 16         else {
 17             while (current.next != null) {//从第一个节点开始判断,非空,再赋值后移
 18                 current = current.next;
 19             }
 20             current.next = newNode;
 21         }
 22     }
 23     public  void  deleteNode(int target){//删除目标元素
 24         Node current = head;
 25         if (head.next == null) {
 26             System.out.println("链表为空,无法删除");
 27             return;
 28         }
 29         while(current.next != null){
 30             if(current.next.data == target){
 31                current.next = current.next.next;
 32                System.out.println("已成功删除节点:"+target);
 33                return;
 34             }
 35             current = current.next;
 36         }
 37         System.out.println("该元素不存在无法删除!");
 38     }
 39     public boolean  searchNode(int target){//查询目标元素是否存在
 40         Node current = head;
 41         if(head.next == null) {
 42             System.out.println("链表为空,无法查找!");
 43             return false;
 44         }
 45         while(current.next != null){
 46             if (current.next.data == target){
 47                 System.out.println("查找到节点"+target);
 48                 return true;
 49             }
 50             current = current.next;
 51         }
 52         return false;
 53     }
 54 
 55     public void printLinkList(){
 56         Node current = head;
 57         if(head.next == null) {
 58             System.out.println("链表为空,无法打印");
 59             return;
 60         }
 61         System.out.println("链表打印:");
 62         while(current.next != null){//从第一个节点开始判断,非空,再赋值后移
 63             current = current.next;
 64             System.out.println(current.data);
 65         }
 66     }
 67     class Node{
 68         int data;
 69         Node next;
 70 
 71         public Node(){
 72             this.data = data;
 73         }
 74 
 75         public Node(int data){
 76             this.data = data;
 77         }
 78     }
 79 
 80     //面试题4:输入一个链表,从尾到头打印链表每个节点的值
 81     //利用栈后进先出的特性
 82 
 83     public class ListNode {
 84         int val;
 85         ListNode next = null;
 86 
 87         ListNode(int val) {
 88             this.val = val;
 89         }
 90     }
 91     public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
 92         Stack<Integer> stack = new Stack<>();
 93         while(listNode != null){
 94             stack.push(listNode.val);
 95             listNode = listNode.next;
 96         }
 97         ArrayList<Integer> list = new ArrayList<>();
 98         while (!stack.empty()){
 99            list.add(stack.pop());
100         }
101         return list;
102         
103     }
104     public static void main(String args[]){
105         LinkList linkList = new LinkList();
106         Scanner cin = new Scanner(System.in);
107         int num = cin.nextInt();
108         while(num != -1){
109             linkList.addNode(num);
110             num = cin.nextInt();
111         }
112         linkList.deleteNode(5);
113         System.out.println(linkList.searchNode(3));
114         linkList.printLinkList();
115     }
116 
117 }

补充:

面试题18

题目1:在给定单向链表的头指针和一个节点指针(指向要删除的节点),在O(1)时间删除链表的节点

思路:分为三种情况

1、链表为空或要删除的节点为空,返回提示

2、要删除的节点不是尾节点,将要删除的节点(current)的下一个节点(current.next)的值都赋给current,然后直接删除current

3、要删除的节点是为尾节点,找到尾部节点,正常删除。

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

 思路:设置指针temp指向当前节点,判断若当前节点不等于下一个节点,则将temp节点赋给index,若相等,则将temp移动到不重复节点处再赋给index

 1  public ListNode deleteDuplication(ListNode pHead)
 2     {
 3             ListNode result;
 4             ListNode temp=pHead;//当前负责移动判断的节点,这里头结点即为第一个节点
 5             ListNode index=new ListNode(1);//指向目前为止未重复的节点
 6             index.next=pHead;
 7             result=index;
 8             while(temp!=null){
 9                 if(temp.next!=null&&temp.next.val==temp.val){//判断当前节点和下一个节点是否相等,若相等,则移动并找到不相等为止的节点
10                     while(temp.next!=null&&temp.next.val==temp.val){
11                         temp=temp.next;
12                     }
13                     temp=temp.next;//最后一个重复节点的下一个节点
14                     index.next=temp;
15                 }
16                 else{
17                     index=index.next;
18                     temp=temp.next;
19                 }
20             }
21             return result.next;
22     }

 面试题22:输入一个链表,输出该链表中倒数第k个结点。

思路:设置两个指针first和second,first走到第k个节点的时候,second在第一个节点处,接着同时向后移动

注意特殊情况的处理:

  1. 链表为空状态,或者k<=0情况,返回空节点
  2. k大于链表长度的情况,返回空节点,在第一个while循环结束后若k>1则链表长度小于k。
 1     public ListNode FindKthToTail(ListNode head,int k) {
 2         ListNode first = head,second = head;
 3         if(head == null || k <= 0) {
 4             return null;}
 5         while(k > 1 && first.next != null){
 6             first = first.next;
 7             k--;
 8         }
 9         if(k == 1){
10             while(first.next != null){
11                 first = first.next;
12                 second = second.next;
13             }
14         }
15         else second = null;
16         return second;
17     }

 面试题23:链表中环的路口

思路:将问题分为两个步骤(将复杂问题分解成多个步骤)

  1. 找出环中任意一个节点:设置两个指针fast和low,fast每次走两步,low走一步,当两个指针相遇的时候,一定是在环中相遇。(注:当遇到尾节点的时候说明无环,则返回null)
  2. 找到环的入口节点:fast回到头结点,low不变,连个结点每次同时走一步,相遇时则为环的入口节点。(可证明)
 1 public ListNode EntryNodeOfLoop(ListNode pHead)
 2 {
 3         ListNode fast = pHead,low = pHead;
 4         if(pHead == null || pHead.next == null) return null;
 5         while(fast != null && fast.next != null){
 6                 low = low.next;
 7                 fast = fast.next.next;
 8                 if(low == fast){    //找到相遇节点时
 9                     fast = pHead;   //fast回到头结点
10                     while(fast != low){
11                         fast = fast.next;
12                         low = low.next;
13                     }
14                     return low;
15                 }
16             }
17         return null;
18 }

 面试题24:输入一个链表,反转链表后,输出链表的所有元素

思路:分两种情况(链表为空或只有一个节点,链表不止一个节点)

 1 public ListNode ReverseList(ListNode head) {
 2         ListNode current = head,pre = null,pnext = null,newHead = null;
 3         if(head == null || head.next == null) return head;
 4         while(current!= null){
 5             pnext = current.next;
 6             if(pnext == null) newHead = current;//一旦发现下一个节点为空,当前节点为最终头结点
 7             current.next = pre;
 8             pre = current;
 9             current = pnext;
10         }
11         return newHead;
12     }

面试题25:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路:每次都将两个链表的头部进行比较,小的看成是新的头结点,头节点的下一个节点就是新的merge,使用递归

           注意任意一个链表为空的状态

 1 public ListNode Merge(ListNode list1,ListNode list2) {
 2         if(list1 == null) return list2;
 3         if(list2 == null) return list1;
 4         ListNode pmHead = null;
 5         if(list1!= null && list2 !=null){
 6             if(list1.val <= list2.val){
 7                 pmHead = list1;
 8                 pmHead.next = Merge(list1.next,list2);
 9             }
10             else
11             {
12                 pmHead = list2;
13                 pmHead.next = Merge(list1,list2.next);
14             }
15         }
16         return pmHead;
17         
18     }

 面试题24:输入两个链表,找出它们的第一个公共结点。(y型)O(m+n):节省空间

思路:分别计算两个链表的长度,根据长度的差值,长的链表先走差值的步数,然后两个链表同时移动对比。

   注意空链表情况以及无公共节点的情况。

另一种思路:使用两个栈分别存放两个链表的节点,从尾部向前比较,返回最后一个公共节点。O(m+n)

 1 public class Solution {
 2     public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
 3         if(pHead1 == null || pHead2 == null)  return null;
 4         ListNode current = pHead1,current1;
 5         int num1 = 0,num2 = 0;
 6         while(current != null){
 7             num1++;
 8             current = current.next;
 9         }
10         current = pHead2;
11         while(current != null){
12             num2++;
13             current = current.next;
14         }
15         if(num1 > num2) {
16             num1 = num1 - num2;
17             current = pHead1;
18             current1 = pHead2;
19         }else{
20             num1 = num2 - num1;
21             current = pHead2;
22             current1 = pHead1;
23         }
24         while(num1 > 0){
25             current = current.next;
26             num1 --;
27         }
28         while(current !=null && current1 !=null){
29             if(current == current1) return current;
30             else{
31                 current = current.next;
32                 current1 = current1.next;
33             }
34         }
35         return null;
36     }
37 }

 

 

 

 

posted @ 2018-04-12 17:33  菩提本无树呀~  阅读(137)  评论(0编辑  收藏  举报