• 剑指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 }

     

  • 相关阅读:
    21-MySQL-Ubuntu-快速回到SQL语句的行首和行末
    2- SQL语句的强化
    1-数据准备
    20-MySQL-Ubuntu-数据表的查询-子查询(九)
    19-MySQL-Ubuntu-数据表的查询-自关联(八)
    18-MySQL-Ubuntu-数据表的查询-连接(七)
    17-MySQL-Ubuntu-数据表的查询-分页(六)
    16-MySQL-Ubuntu-数据表的查询-分组与聚合(五)
    15-MySQL-Ubuntu-数据表的查询-聚合函数(四)
    14-MySQL-Ubuntu-数据表的查询-范围查询(三)
  • 原文地址:https://www.cnblogs.com/lizijiangmm/p/8809197.html
Copyright © 2020-2023  润新知