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) **