面试算法之——链表

0. 自建链表

class ListNode{
    int val;
    ListNode next;
    ListNode(int val){
        this.val=val;
    }
}

        Scanner sc = new Scanner(System.in);
        String[] str = sc.nextLine().split(" ");
          
        //链表头
        ListNode head = new ListNode(0);
        //链表尾先指向头
        ListNode tail = head;

        for(int i=0;i

1. 删除节点:

  1. 删除链表的倒数第N个节点
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        /*
        删除链表的倒数第N个节点
        7.22
        */
        //创建新链表存储,保存head节点,先循环计算链表的长度,再循环跳过倒数第n个节点

        //判断空
        if(head == null){
            return null;
        }

        //创建新链表存储
        ListNode node = new ListNode(0);
        node.next = head;

        //计算链表长度
        int len = 0;
        ListNode cur = head;
        while(cur != null){
            len++;
            cur = cur.next;
        }

        //重置cur指向node,将节点存入node链表
        cur = node;
        int index = 0;
        //循环找到倒数第n个节点前的节点
        for(int i=0;i
  1. 删除重复不保留
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        /*
        删除排序链表中的重复元素,不保留
        7.24
        */
        //双指针

        //判断空
        if(head == null){
            return null;
        }

        //暂存head
        ListNode node = new ListNode(0);
        node.next = head;

        ListNode cur = node;

        while(cur.next != null && cur.next.next != null){
            //如果出现重复
            if(cur.next.val == cur.next.next.val){
                ListNode temp = cur.next;
                //判断空
                while(temp != null && temp.next != null && temp.val == temp.next.val){
                    temp = temp.next;
                }

                cur.next = temp.next;
            }else{
                cur = cur.next;
            }
        }
        return node.next;
    }
}
  1. 删除重复保留
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        /*
        删除排序链表的重复元素,保留
        7.24
        */
        //双指针

        //判断空
        if(head == null){
            return null;
        }

        ListNode cur = head;

        while(cur != null && cur.next != null){
            if(cur.val == cur.next.val){
                cur.next = cur.next.next;
            }else{
                cur = cur.next;
            }
        }

        return head;
    }
}
  1. 返回倒数第K个节点
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {

        //快指针先走k,然后快慢指针一起走,跳出while循环时,慢指针就是倒数第K个节点

        ListNode fast = head;
        ListNode slow = head;

        //快指针先走k
        while(k-- > 0){
            fast = fast.next;
        }

        //一起走
        while(fast != null){
            fast = fast.next;
            slow = slow.next;
        }

        //当跳出while循环时,slow指针就是倒数第K个节点
        return slow;
    }
}

2. 合并链表:

  1. 合并两个有序链表
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        /*
        合并两个有序链表
        7.22
        */
        //创建新链表存储,分治合并,补录

        ListNode node = new ListNode(0);
        
        ListNode cur = node;

        while(l1 != null && l2 != null){
            if(l1.val < l2.val){
                cur.next = l1;
                l1 = l1.next;
            }else{
                cur.next = l2;
                l2 = l2.next;
            }
            cur = cur.next;
        }

        //补录
        if(l1 != null){
            cur.next = l1;
        }
        if(l2 != null){
            cur.next = l2;
        }

        return node.next;
    }
}
  1. 合并K个有序链表
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        /*
        合并K个排序链表
        7.22
        */
        //分治 + 合并

        if(lists.length == 0){
            return null;
        }

        return Merge(lists,0,lists.length-1);
    }

    public ListNode Merge(ListNode[] lists,int start,int end){
        //递归出口
        if(start == end){
            return lists[start];
        }

        //提取数组中点
        int middle = start + (end - start)/2;

        //递归形成左右链表
        ListNode left = Merge(lists,start,middle);
        ListNode right = Merge(lists,middle+1,end);

        //合并
        return MergeTwo(left,right);
    }

    public ListNode MergeTwo(ListNode left,ListNode right){
        
        ListNode node = new ListNode(0);
        
        ListNode cur = node;

        while(left != null && right != null){
            if(left.val < right.val){
                cur.next = left;
                left = left.next;
            }else{
                cur.next = right;
                right = right.next;
            }
            cur = cur.next;
        }

        if(left != null){
            cur.next = left;
        }
        if(right != null){
            cur.next = right;
        }

        return node.next;
    }
}

3. 翻转链表:

  1. 两两交换链表节点
class Solution {
    public ListNode swapPairs(ListNode head) {
        /*
        两两交换链表节点
        7.22
        */
        //递归翻转,翻转后的尾指向翻转前的头

        //递归出口
        if(head == null || head.next == null){
            return head;
        }

        ListNode pre = head;
        ListNode tail = head.next;

        //pre.next指向tail.next递归
        pre.next = swapPairs(tail.next);

        //tail.next指向pre
        tail.next = pre;

        //翻转后tail是链表头
        return tail;
    }
}
  1. K个一组翻转链表
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        /*
        K个一组翻转链表
        7.22
        */
        //递归翻转

        //递归出口
        if(head == null || head.next == null){
            return head;
        }

        ListNode cur = head;
        //for循环到第k个节点的前一个节点
        for(int i=0;i
  1. 翻转m到n的链表
class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        /*
        反转从m到n的链表
        7.25
        */
        //先遍历找到m节点,反转从m到n的节点,拼接头尾

        //判断空
        if(head == null){
            return null;
        }

        ListNode node = new ListNode(0);
        node.next = head;

        ListNode cur = node;

        //for循环找到第m个节点的前一个节点cur
        for(int i=1;i
  1. 翻转链表
class Solution {
    public ListNode reverseList(ListNode head) {
        /*
        反转链表
        7.26
        */
        //双指针,递归

        //递归出口
        // if(head == null || head.next == null){
        //     return head;
        // }

        // //递归到最后一个节点
        // ListNode cur = reverseList(head.next);

        // //head.next.next拼接head
        // head.next.next = head;

        // head.next = null;

        // return cur;

        ListNode pre = null;
        ListNode next = null;

        while(head != null){
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }

        return pre;
        
    }
}

4. 环形链表:

  1. 判断有无环
public class Solution {
    public boolean hasCycle(ListNode head) {
        /*
        判断链表是否有环
        7.23
        */
        //方法一:哈希Set存节点
        //方法二:快慢指针

        // Set set = new HashSet<>();
        // while(head != null){
        //     if(set.contains(head)){
        //         return true;
        //     }

        //     set.add(head);

        //     head = head.next;
        // }
        // return false;

        //判断head和head.next是否为null,如果是,必定无环
        if(head == null || head.next == null){
            return false;
        }

        ListNode fast = head;
        ListNode slow = head;

        while(true){
            //无环
            if(fast == null || fast.next == null){
                return false;
            }

            //快走2慢走1
            fast = fast.next.next;
            slow = slow.next;

            //如果fast能追上slow,说明有环,break
            if(fast == slow){
                break;
            }
        }

        return true;
    }
}
  1. 返回环入口
public class Solution {
    public ListNode detectCycle(ListNode head) {
        /*
        判断链表是否有环,并找出
        7.23
        */
        //方法一:哈希Set
        //方法二:双指针

        // Set set = new HashSet<>();
        // while(head != null){
        //     if(set.contains(head)){
        //         return head;
        //     }
        //     set.add(head);
        //     head = head.next;
        // }

        // return null;

        if(head == null || head.next == null){
            return null;
        }

        ListNode fast = head;
        ListNode slow = head;

        while(true){
            //无环
            if(fast == null || fast.next == null){
                return null;
            }

            //快走2慢走1
            fast = fast.next.next;
            slow = slow.next;

            //如果fast能追上slow,说明有环,break
            if(fast == slow){
                break;
            }
        }

        fast = head;
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }

        return fast;
    }
}

5. 其他

  1. 两数相加
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {

        /*
        两数相加
        7.22
        */
        //柱式相加,node存入十位,node.next存个位   
        //carry进位为0
        return add(l1,l2,0);
    }

    public ListNode add(ListNode l1,ListNode l2,int carry){

        //递归出口
        if(l1 == null && l2 == null && carry == 0){
            return null;
        }

        //如果l1为null,置为0
        if(l1 == null){
            l1 = new ListNode(0);
        }
        if(l2 == null){
            l2 = new ListNode(0);
        }

        //sum
        int sum = l1.val + l2.val + carry;

        //创建节点
        ListNode node = new ListNode(sum%10);

        //拼接递归结果
        node.next = add(l1.next,l2.next,sum/10);
        return node;
    }
}
  1. 回文链表
class Solution {
    public boolean isPalindrome(ListNode head) {
        /*
        回文链表
        7.23
        */
        //先快慢指针找到中点,分割左右两条链表。再翻转后半链表,与前半链表逐一比较

        ListNode node = new ListNode(0);
        //保存head节点
        node.next = head;

        ListNode fast = node;
        ListNode slow = node;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }

        //fast作为后半链表的头节点
        fast = slow.next;

        //断开后半
        slow.next = null;
        slow = node.next;

        //翻转后半
        ListNode pre = null;
        ListNode next = null;
        while(fast != null){
            next = fast.next;
            fast.next = pre;
            pre = fast;
            fast = next;
        }

        //while比较
        while(pre != null){
            if(pre.val != slow.val){
                return false;
            }

            pre = pre.next;
            slow = slow.next;
        }
        return true;
    }
}

你可能感兴趣的:(面试算法之——链表)