3.17 链表

This commit is contained in:
zhangsan 2025-03-18 09:09:22 +08:00
parent 5218596c0a
commit b9c0de8d1b
14 changed files with 446 additions and 3 deletions

View File

@ -0,0 +1,36 @@
package linkedlist;
/**
* 题目 2. 两数相加 (mergeTwoLists)
* 描述给你两个 非空 的链表表示两个非负的整数它们每位数字都是按照 逆序 的方式存储的并且每个节点只能存储 一位 数字
* 请你将两个数相加并以相同形式返回一个表示和的链表
* 你可以假设除了数字 0 之外这两个数都不会以 0 开头
* 链接https://leetcode.cn/problems/add-two-numbers/
*/
public class AddTwoNumbers {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(-1);
ListNode current = dummy;
int carry = 0;
while(l1 != null || l2 != null) {
int x = (l1 != null) ? l1.val : 0;
int y = (l2 != null) ? l2.val : 0;
int sum = x + y + carry;
current.next = new ListNode(sum % 10);
current = current.next;
carry = sum / 10;
if(l1 != null) l1 = l1.next;
if(l2 != null) l2 = l2.next;
}
if(carry > 0) {
current.next = new ListNode(carry);
}
return dummy.next;
}
}

View File

@ -0,0 +1,46 @@
package linkedlist;
import java.util.HashMap;
/**
* 题目 138. 随机链表的复制 (copyRandomList)
* 描述给你一个长度为 n 的链表每个节点包含一个额外增加的随机指针 random 该指针可以指向链表中的任何节点或空节点
*
* 构造这个链表的 深拷贝 深拷贝应该正好由 n 全新 节点组成其中每个新节点的值都设为其对应的原节点的值新节点的 next 指针和 random 指针也都应指向复制链表中的新节点并使原链表和复制链表中的这些指针能够表示相同的链表状态复制链表中的指针都不应指向原链表中的节点
*
* 例如如果原链表中有 X Y 两个节点其中 X.random --> Y 那么在复制链表中对应的两个节点 x y 同样有 x.random --> y
*
* 返回复制链表的头节点
*
* 用一个由 n 个节点组成的链表来表示输入/输出中的链表每个节点用一个 [val, random_index] 表示
*
* val一个表示 Node.val 的整数
* random_index随机指针指向的节点索引范围从 0 n-1如果不指向任何节点则为 null
* 你的代码 接受原链表的头节点 head 作为传入参数
* 链接https://leetcode.cn/problems/copy-list-with-random-pointer/
*/
//不会做 需要重做
public class CopyRandomList {
public Node copyRandomList(Node head) {
if (head == null)
return null;
HashMap<Node, Node> map = new HashMap<>(); // 原节点 -> 新节点映射
Node curr = head;
// 第一次遍历创建新节点并建立映射
while (curr != null) {
map.put(curr, new Node(curr.val));
curr = curr.next;
}
// 第二次遍历设置next和random指针
curr = head;
while (curr != null) {
Node clone = map.get(curr);
clone.next = map.get(curr.next);
clone.random = map.get(curr.random);
curr = curr.next;
}
return map.get(head);
}
}

View File

@ -0,0 +1,53 @@
package linkedlist;
import java.util.HashSet;
/**
* 题目 142. 环形链表 II (detectCycle)
* 描述给定一个链表的头节点 head 返回链表开始入环的第一个节点 如果链表无环则返回 null
* 如果链表中有某个节点可以通过连续跟踪 next 指针再次到达则链表中存在环 为了表示给定链表中的环评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置索引从 0 开始如果 pos -1则在该链表中没有环注意pos 不作为参数进行传递仅仅是为了标识链表的实际情况
* 不允许修改 链表
* 链接https://leetcode.cn/problems/linked-list-cycle-ii/
*/
public class DetectCycle {
//哈希
public ListNode detectCycle1(ListNode head) {
ListNode pos = head;
HashSet<ListNode> visited = new HashSet<ListNode>();
while (pos != null) {
if (visited.contains(pos)) {
return pos;
} else {
visited.add(pos);
}
pos = pos.next;
}
return null;
}
//Floyd 快慢指针
public ListNode detectCycle(ListNode head) {
if (head == null) {
return null;
}
ListNode slow = head, fast = head;
while (fast != null) {
slow = slow.next;
if (fast.next != null) {
fast = fast.next.next;
} else {
return null;
}
if (fast == slow) {
ListNode ptr = head;
while (ptr != slow) {
ptr = ptr.next;
slow = slow.next;
}
return ptr;
}
}
return null;
}
}

View File

@ -0,0 +1,76 @@
package linkedlist;
import java.util.HashSet;
/**
* 题目 141. 环形链表 (hasCycle)
* 描述给你一个链表的头节点 head 判断链表中是否有环
* 如果链表中有某个节点可以通过连续跟踪 next 指针再次到达则链表中存在环 为了表示给定链表中的环评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置索引从 0 开始注意pos 不作为参数进行传递 仅仅是为了标识链表的实际情况
* 如果链表中存在环 则返回 true 否则返回 false
* 链接https://leetcode.cn/problems/linked-list-cycle/
输入head = [3,2,0,-4], pos = 1
输出true
解释链表中有一个环其尾部连接到第二个节点
*/
public class HasCycle {
//哈希法
public boolean hasCycle1(ListNode head) {
HashSet<ListNode>set=new HashSet<>();
ListNode temp=head;
while (temp!=null) {
if (!set.contains(temp))
set.add(temp);
else
return true;
temp = temp.next;
}
return false;
}
//翻转指针
public boolean hasCycle2(ListNode head) {
// 如果链表为空或者只有一个节点直接返回无环
if (head == null || head.next == null) {
return false;
}
// originalHead 保存最初的头节点
ListNode originalHead = head;
// head.next 开始遍历先把 head 与链表分离
ListNode cur = head.next;
ListNode pre = head;
// 断开 head 和后面的连接
head.next = null;
while (cur != null) {
// 如果当前节点又指回了 originalHead则说明出现环
if (cur == originalHead) {
return true;
}
// 反转指针
ListNode temp = cur.next;
cur.next = pre;
// 移动 pre cur
pre = cur;
cur = temp;
}
// 走到空指针说明无环
return false;
}
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head.next;
while (slow != fast) {
if (fast == null || fast.next == null) {
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
}

View File

@ -7,4 +7,5 @@ public class ListNode {
val = x;
next = null;
}
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

View File

@ -0,0 +1,38 @@
package linkedlist;
import java.util.ArrayList;
import java.util.List;
/**
* 题目 21. 合并两个有序链表 (mergeTwoLists)
* 描述将两个升序链表合并为一个新的 升序 链表并返回新链表是通过拼接给定的两个链表的所有节点组成的
* 链接https://leetcode.cn/problems/merge-two-sorted-lists/
*/
public class MergeTwoLists {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode head = new ListNode(-1);
ListNode mv = head;
ListNode mv1 = list1;
ListNode mv2 = list2;
while(mv1 != null && mv2 !=null) {
if(mv1.val < mv2.val) {
mv.next = mv1;
mv1 = mv1.next;
}
else {
mv.next = mv2;
mv2 = mv2.next;
}
mv = mv.next;
}
if(mv1 == null) {
mv.next = mv2;
}
else {
mv.next = mv1;
}
return head.next;
}
}

View File

@ -0,0 +1,13 @@
package linkedlist;
public class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}

View File

@ -0,0 +1,47 @@
package linkedlist;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
/**
* 题目 19. 删除链表的倒数第 N 个结点 (removeNthFromEnd)
* 描述给你一个链表删除链表的倒数第 n 个结点并且返回链表的头结点
* 链接https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
*/
public class RemoveNthFromEnd {
public ListNode removeNthFromEnd1(ListNode head, int n) {
HashMap<Integer,ListNode>map=new HashMap<>();
int k=0;
ListNode cur=head;
while (cur!=null){
map.put(k++,cur);
cur=cur.next;
}
if(k-n==0)
return head.next;
ListNode pre=map.get(k-n-1);
pre.next= map.get(k-n+1);
return head;
}
//入栈 出栈
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0,head);
Deque<ListNode> stack = new LinkedList<>();
ListNode cur = dummy;
while (cur != null) {
stack.push(cur);
cur = cur.next;
}
for (int i = 0; i < n; ++i) {
stack.pop();
}
ListNode prev = stack.peek();
prev.next = prev.next.next;
ListNode ans = dummy.next;
return ans;
}
}

View File

@ -0,0 +1,31 @@
package linkedlist;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 题目 148. 排序链表 (sortList)
* 描述给你链表的头结点 head 请将其按 升序 排列并返回 排序后的链表
* 链接https://leetcode.cn/problems/sort-list/
*/
public class SortList {
public ListNode sortList(ListNode head) {
ListNode cur=head;
List<Integer>list=new ArrayList<>();
while (cur!=null){
list.add(cur.val);
cur=cur.next;
}
Collections.sort(list);
ListNode pre=new ListNode(-1);
ListNode newnode=pre;
for (Integer integer : list) {
pre.next= new ListNode(integer);
pre=pre.next;
}
return newnode.next;
}
}

View File

@ -0,0 +1,41 @@
package linkedlist;
/**
* 题目 24. 两两交换链表中的节点 (swapPairs)
* 描述给你一个链表两两交换其中相邻的节点并返回交换后链表的头节点你必须在不修改节点内部的值的情况下完成本题只能进行节点交换
* 链接https://leetcode.cn/problems/swap-nodes-in-pairs/
*/
//需重做
public class SwapPairs {
//只有一个节点或没有节点时无需交换
//递归
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode one = head;
ListNode two = one.next;
ListNode three = two.next;
two.next = one;
one.next = swapPairs(three);
return two;
}
//迭代好理解
public ListNode swapPairs1(ListNode head) {
ListNode dummyHead = new ListNode(0,head);
ListNode temp = dummyHead;
while (temp.next != null && temp.next.next != null) {
ListNode node1 = temp.next;
ListNode node2 = temp.next.next;
temp.next = node2;
node1.next = node2.next;
node2.next = node1;
temp = node1;
}
return dummyHead.next;
}
}

View File

@ -1,9 +1,6 @@
package substring;
import hash.Test;
import java.util.HashMap;
import java.util.Iterator;
/**
* 题目523. 连续的子数组和 (checkSubarraySum)

View File

@ -0,0 +1,47 @@
package tree;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
/**
* 题目 94. 二叉树的中序遍历 (inorderTraversal)
* 描述给定一个二叉树的根节点 root 返回 它的 中序 遍历
* 链接https://leetcode.cn/problems/binary-tree-inorder-traversal/
*/
//递归会 迭代需记一下
public class InorderTraversal {
//递归
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorder(root, res);
return res;
}
public void inorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
inorder(root.left, res);
res.add(root.val);
inorder(root.right, res);
}
//迭代+
public List<Integer> inorderTraversal1(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Deque<TreeNode> stk = new ArrayDeque<>();
while (root != null || !stk.isEmpty()) {
while (root != null) {
stk.push(root);
root = root.left;
}
root = stk.pop();
res.add(root.val);
root = root.right;
}
return res;
}
}

View File

View File

@ -0,0 +1,17 @@
package tree;
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {
}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}