leetcode刷题之链表List相关之环形链表与K个一组翻转列表

449 阅读2分钟

K个一组翻转列表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 k 是一个正整数,它的值小于或等于链表的长度。 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 示例:

给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5

链接

解题分析

  • 利用栈先进后出的特性实现翻转
  • 首先先计算链表的长度,方便后续的分组和计算
  • 建立一个作为临时存储结果的栈和结果链表
  • 分组对链表进行循环遍历,将每个分组里面的值按顺序压入栈中,每一组的入栈完成之后弹出并添加到结果链表当中
  • 循环结束之后,将不在任何分组内的子链表的头指针追加到结果链表当中
  • 返回结果链表的头指针
package LT;/*
 * Created by lizeyu on 2020/9/13 0:55
 */

import java.util.Stack;

public class ReversedLinkedListByStack {
    public class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
    }

    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode curr = head;
        int length = 0;
        while (head != null) {
            length++;
            head = head.next;
        }
        Stack<Integer> stack = new Stack<>();
        ListNode result = new ListNode(0);
        ListNode dummyNode = result;
        for (int i = 0; i < length / k; i++) {
            for (int j = 0; j < k; j++) {
                stack.push(curr.val);
                curr = curr.next;
            }
            while (!stack.isEmpty()) {
                result.next = new ListNode(stack.pop());
                result = result.next;
            }
        }
        if (curr != null) {
            result.next = curr;
        }
        return dummyNode.next;
    }

}

** 时间复杂度:O(N),N是链表的长度,空间复杂度:需要用到额外空间-栈,为O(N) **

迭代法,多指针记录的方式

  • 这里需要用到翻转链表的函数
package LT;/*
 * Created by lizeyu on 2020/9/12 23:08
 */

public class ReverseNodesInKGroups {
    public class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
    }

    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode dummyNode = new ListNode(0);
        dummyNode.next = head;
        ListNode pre = dummyNode, end = dummyNode;
        while (end.next != null) {
            for (int i = 0; i < k; i++) {
                if (end == null) {
                    break;
                }
                end = end.next;
            }
            if (end==null){
                break;
            }
            ListNode next = end.next;
            ListNode start = pre.next;
            end.next = null;
            pre.next = reverseList(start);
            start.next = next;
            pre = start;
            end = pre;
        }
        return dummyNode.next;
    }

    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode temp = curr.next;
            curr.next = pre;
            pre = curr;
            curr = temp;
        }
        return pre;
    }
}

环形链表2

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

链接

哈希表

解题分析

  • 遍历所有的结点并在hashSet(集合,不允许重复)当中存储每个结点的引用(或者内存地址)。如果当前结点是空结点,则证明遍历到了链表的末尾且没有环,那么返回null。如果当前结点的引用出现在hashSet当中的话,那么返回当前遍历到的结点
package LT;/*
 * Created by lizeyu on 2020/9/13 16:11
 */

import java.util.HashSet;

public class LinkedListCycle2BySet {
    public class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
    }
    public ListNode detectCycle(ListNode head) {
        HashSet<ListNode> hashSet = new HashSet<>();
        while (head!=null){
            if (hashSet.contains(head)){
                return head;
            }
            hashSet.add(head);
            head = head.next;
        }
        return null;
    }
}

快慢指针方法

public class Solution {
    private ListNode getIntersect(ListNode head) {
        ListNode tortoise = head;
        ListNode hare = head;
        while (hare != null && hare.next != null) {
            tortoise = tortoise.next;
            hare = hare.next.next;
            if (tortoise == hare) {
                return tortoise;
            }
        }

        return null;
}

    public ListNode detectCycle(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode intersect = getIntersect(head);
        if (intersect == null) {
            return null;
        }
        ListNode ptr1 = head;
        ListNode ptr2 = intersect;
        while (ptr1 != ptr2) {
            ptr1 = ptr1.next;
            ptr2 = ptr2.next;
        }

        return ptr1;
    }
}

环形链表

定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

链接

哈希表 需要额外的空间

解题分析

  • 遍历所有的结点并在hashSet(集合,不允许重复)当中存储每个结点的引用(或者内存地址)。如果当前结点是空结点,则证明遍历到了链表的末尾且没有环,那么返回false。如果当前结点的引用出现在hashSet当中的话,那么返回true
package LT;/*
 * Created by lizeyu on 2020/9/13 11:57
 */

import java.util.HashSet;

public class LinkedListCycle {
    public class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
    }
    public boolean hasCycle(ListNode head) {
        HashSet<ListNode> hashSet = new HashSet<>();
        while (head!=null){
            if (hashSet.contains(head)){
                return true;
            }
            else{
                hashSet.add(head);
                head = head.next;
            }
        }
        return false;
    }
}

** 时间复杂度:O(N),对于有n个元素的链表,我们访问每个元素最多一次,添加一个结点到哈希表需要花费O(1)的时间**

** 空间复杂度:取决于添加到哈希表中的元素数目,最多可以添加n个元素 **

快慢指针方法,不需要额外的空间消耗,空间复杂度可以将降到O(1)

解题分析

  • 用起始点不同的两个快慢指针进行移动,慢指针每次移动一步,快指针每次移动两步
    • 如果当前链表不存在环,那么快指针会碰到null的结点,那么此时返回false
    • 如果当前链表中存在环,快指针一定会追上慢指针,那么可以返回true
    • 可以想象为跑道赛跑
package LT;/*
 * Created by lizeyu on 2020/9/13 12:13
 */

public class LinkedListCycleBySlowFastPointers {
    public class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
    }

    public boolean hasCycle(ListNode head) {
        if (head == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null || fast.next.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }
}

** 空间复杂度:只使用了快慢指针,所以空间复杂度是O(1) **

** 时间复杂度:O(N) **