21.合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
解决方案
方法一: 普通方法
private static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null && l2 == null) {
return null;
}
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
ListNode head = new ListNode(0);
ListNode index = head;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
head.next = l1;
l1 = l1.next;
} else {
head.next = l2;
l2 = l2.next;
}
head = head.next;
}
if (l1 == null) {
head.next = l2;
}
if (l2 == null) {
head.next = l1;
}
return index.next;
}
方法二:递归
private static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null && l2 == null) {
return null;
}
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
ListNode head;
if (l1.val < l2.val) {
head = l1;
head.next = mergeTwoLists(l1.next, l2);
} else {
head = l2;
head.next = mergeTwoLists(l1, l2.next);
}
return head;
}
26. 删除排序数组中的重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成
示例 1:
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2
示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4
方法:双指针法
private static int removeDuplicates(int[] nums) {
if (nums.length == 0) return 0;
int i = 0;
for (int j = 1; j < nums.length; j++) {
// 跳过重复的项
if (nums[j] != nums[i]) {
i++;
nums[i] = nums[j];
}
}
return i + 1;
}
复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)
27. 移除元素
给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2
你不需要考虑数组中超出新长度后面的元素
示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4
解决方案
方法一:双指针
两个指针 i 和 j,其中 i 是慢指针,j 是快指针
privare static int removeElement(int[] nums, int val) {
int i = 0;
for (int j = 0; j < nums.length; j++) {
if (nums[j] != val) {
nums[i] = nums[j];
i++;
}
}
return i;
}
复杂度分析
时间复杂度:O(n),假设数组总共有 n 个元素,i 和 j 至少遍历 2n 步
空间复杂度:O(1)
方法二:双指针 —— 当要删除的元素很少时
遇到 nums[i] = val 时,我们可以将当前元素与最后一个元素进行交换,并释放最后一个元素。这实际上使数组的大小减少了 1
请注意,被交换的最后一个元素可能是您想要移除的值。但是不要担心,在下一次迭代中,我们仍然会检查这个元素
privare static int removeElement(int[] nums, int val) {
int i = 0;
int n = nums.length;
while (i < n) {
if (nums[i] == val) {
nums[i] = nums[n - 1];
// reduce array size by one
n--;
} else {
i++;
}
}
return n;
}
复杂度分析
时间复杂度:O(n),i 和 j 最多遍历 n 步
空间复杂度:O(1)
28. 实现 strStr()
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = “hello”, needle = “ll”
输出: 2
示例 2:
输入: haystack = “aaaaa”, needle = “bba”
输出: -1
说明:
当 needle 是空字符串时,我们应当返回 0
自己写的
private static int strStr(String haystack, String needle) {
if (haystack == null || needle == null) {
return -1;
}
if (haystack.length() == 0) {
if (needle.length() != 0) {
return -1;
}
} else {
if (needle.length() == 0) {
return 0;
}
}
if (haystack.length() < needle.length()) {
return -1;
}
if (haystack.equals(needle)) {
return 0;
}
char[] hs = haystack.toCharArray();
char[] ns = needle.toCharArray();
int k = 0;
for (int i = 0; i < hs.length; i++) {
if (hs[i] == ns[0]) {
for (int j = 0; j < ns.length; j++) {
if (j + i == hs.length) {
return -1;
}
if (hs[j + i] == ns[j]) {
k++;
} else {
k = 0;
break;
}
if (k == ns.length) {
return i;
}
}
}
}
return -1;
}
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置
你可以假设数组中无重复元素
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
private static int searchInsert(int[] nums, int target) {
if (nums == null) {
throw new IllegalArgumentException("your nums is null");
}
if (target <= nums[0]) {
return 0;
} else if (target == nums[nums.length - 1]) {
return nums.length - 1;
} else if (target > nums[nums.length - 1]) {
return nums.length;
}
return getMiddle(nums, 0, nums.length, target);
}
// 二分查找 + 递归:不断缩小范围,最终确定目标值的索引
private static int getMiddle(int[] nums, int start, int end, int target) {
int mid = (start + end) / 2;
if (start == mid) {
return mid + 1;
} else if (start == end) {
return end + 1;
}
if (nums[mid] < target) {
start = mid;
} else if (nums[mid] > target) {
end = mid;
} else {
return mid;
}
return getMiddle(nums, start, end, target);
}