文章目录
合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
迭代法
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0, l1);
ListNode cur = dummy;
while (l1 != null && l2 != null) {
if (l1.val > l2.val) {
cur.next = l2;
l2 = l2.next;
} else {
cur.next = l1;
l1 = l1.next;
}
cur = cur.next;
}
cur.next = l1 == null ? l2 : l1;
return dummy.next;
}
}
递归法
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
} else if (l2 == null) {
return l1;
} else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
迭代法
class Solution {
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode dummy = new ListNode(0, head);
ListNode cur = head;
ListNode pre = dummy;
while (cur != null && cur.next != null) {
pre.next = cur.next;
cur.next = pre.next.next;
pre.next.next = cur;
pre = cur;
cur = cur.next;
}
return dummy.next;
}
}
递归法
class Solution {
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = head.next;
head.next = swapPairs(newHead.next);
newHead.next = head;
return newHead;
}
}
K个一组翻转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
进阶:
你可以设计一个只使用常数额外空间的算法来解决此问题吗?
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
示例 3:
输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]
示例 4:
输入:head = [1], k = 1
输出:[1]
迭代法
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(0, head);
ListNode pre = dummy;
while (head != null) {
ListNode tail = pre;
for (int i = 0; i < k; ++i) {
tail = tail.next;
if (tail == null) {
return dummy.next;
}
}
ListNode nextHead = tail.next;
tail.next = null;
tail = head;
pre.next = myReverse(head);
tail.next = nextHead;
pre = tail;
head = nextHead;
}
return dummy.next;
}
private ListNode myReverse(ListNode head) {
ListNode prev = null;
ListNode cur = head;
while (cur != null) {
ListNode nex = cur.next;
cur.next = prev;
prev = cur;
cur = nex;
}
return prev;
}
}
递归法
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(0, head);
ListNode pre = dummy;
while (head != null) {
ListNode tail = pre;
for (int i = 0; i < k; ++i) {
tail = tail.next;
if (tail == null) {
return dummy.next;
}
}
ListNode nextHead = tail.next;
tail.next = null;
tail = head;
pre.next = myReverse(head);
tail.next = nextHead;
pre = tail;
head = nextHead;
}
return dummy.next;
}
private ListNode myReverse(ListNode head) {
if (head == null || head.next == null) {
return head;
} else {
ListNode tmp = head.next;
ListNode newHead = myReverse(head.next);
tmp.next = head;
head.next = null;
return newHead;
}
}
}
合并两个有序数组
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
双指针法从后往前
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
if (n == 0)
return;
if (m == 0) {
System.arraycopy(nums2, 0, nums1, 0, n);
return;
}
int i = m - 1, j = n - 1, cur = m + n - 1;
while (cur >= 0) {
if (nums1[i] > nums2[j]) {
nums1[cur--] = nums1[i--];
} else {
nums1[cur--] = nums2[j--];
}
if (i < 0) {
System.arraycopy(nums2, 0, nums1, 0, j + 1);
break;
}
if (j < 0)
break;
}
}
}
复制带随机指针的链表
给你一个长度为 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 作为传入参数。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
哈希表存储,两次遍历
class Solution {
public Node copyRandomList(Node head) {
Map<Node, Node> map = new HashMap<>();
Node dummy = new Node(0), newP = dummy, oldP = head;
while (oldP != null) {
newP.next = new Node(oldP.val);
newP = newP.next;
map.put(oldP, newP);
oldP = oldP.next;
}
newP = dummy.next;
oldP = head;
while (oldP != null) {
newP.random = map.get(oldP.random);
newP = newP.next;
oldP = oldP.next;
}
return dummy.next;
}
}
哈希表存储,一次遍历
class Solution {
private Map<Node, Node> map = new HashMap<>();
public Node copyRandomList(Node head) {
Node dummy = new Node(0), newP = dummy, oldP = head;
while (oldP != null) {
newP.next = getNode(oldP);
newP = newP.next;
newP.random = getNode(oldP.random);
oldP = oldP.next;
}
return dummy.next;
}
private Node getNode(Node node) {
if (node == null)
return null;
if (!map.containsKey(node))
map.put(node, new Node(node.val));
return map.get(node);
}
}
在原节点后新增节点
class Solution {
public Node copyRandomList(Node head) {
if (head == null)
return null;
Node cur = head;
while (cur != null) {
Node node = new Node(cur.val);
node.next = cur.next;
cur.next = node;
cur = node.next;
}
cur = head;
while (cur != null) {
if (cur.random != null)
cur.next.random = cur.random.next;
cur = cur.next.next;
}
Node dummy = new Node(0);
cur = head;
Node cur_new = dummy;
while (cur != null) {
cur_new.next = cur.next;
cur_new = cur_new.next;
cur.next = cur_new.next;
cur = cur.next;
}
return dummy.next;
}
}
合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入:
输出:
合并后的树:
注意: 合并必须从两个树的根节点开始。
递归
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null)
return root2;
if (root2 == null)
return root1;
root1.val += root2.val;
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
return root1;
}
}