21. 合并两个有序链表
一:设置虚拟头结点
//执行用时: 0 ms
//内存消耗: 40.9 MB
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while(list1 != null && list2 != null) {
if(list1.val > list2.val) {
cur.next = list2;
list2 = list2.next;
} else {
cur.next = list1;
list1 = list1.next;
}
cur = cur.next;
}
cur.next = list1 == null ? list2 : list1;
return dummy.next;
}
}
二:递归
//执行用时: 0 ms
//内存消耗: 40.7 MB
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null) {
return l2;
}
if(l2 == null) {
return l1;
}
if(l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
22. 括号生成
方法一:回溯
//执行用时: 0 ms
//内存消耗: 41.9 MB
class Solution {
List<String> result = new ArrayList<>();
StringBuilder path = new StringBuilder();
public List<String> generateParenthesis(int n) {
backTracing(n, 0, 0);
return result;
}
public void backTracing(int n, int start, int end) {
if(path.length() == n*2) {
result.add(path.toString());
return ;
}
if(start < n) {
path.append('(');
backTracing(n, start + 1, end);
path.deleteCharAt(path.length() - 1);
}
if(end < start) { //此处end < start,而不是 end < n
path.append(')');
backTracing(n, start, end + 1);
path.deleteCharAt(path.length() - 1);
}
}
}
31. 下一个排列
方法一:模拟+排序
class Solution {
public void nextPermutation(int[] nums) {
for (int i = nums.length - 1; i >= 0; i--) {
for (int j = nums.length - 1; j > i; j--) {
if (nums[j] > nums[i]) {
// 交换
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
// [i + 1, nums.length) 内元素升序排序
Arrays.sort(nums, i + 1, nums.length);
return;
}
}
}
Arrays.sort(nums); // 不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
}
}
class Solution {
public void nextPermutation(int[] nums) {
if(nums.length == 0){
return;
}
int len = nums.length;
//从后向前遍历
for(int i = len-1;i >= 0;i--){
//如果i为0,说明数组从后到前是递增(654321)的,没有更大的了
//直接重排序变成一个递减的(123456)符合题意
if(i == 0){
Arrays.sort(nums);
return;
}else if(nums[i] > nums[i-1]){
//一旦出现后一个数字nums[i]比前一个大,说明存在更大的整数
//对nums[i]及后面的数组排序,从小到大
Arrays.sort(nums,i,len);
for(int j = i;i < len;j++){
//由于从i开始后面已经排序
//那么保证获得比nums[i-1]大的数,是[i,...,len-1]中最小的,交换即可
if(nums[j] > nums[i-1]){
swap(nums,j,i-1);
return;
}
}
}
}
}
public void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
33. 搜索旋转排序数组
方法一:二分
//执行用时: 0 ms
//内存消耗: 41.2 MB
class Solution {
public int search(int[] nums, int target) {
int left=0;
int right= nums.length - 1;
while (left<=right){
int mid =left+ (right-left)/2;
if(nums[mid]==target){
return mid;
}
//分析前半部分,注意此处用小于等于
if(nums[left]<=nums[mid]) {
//target在前半部分
if(target>=nums[left]&&target<nums[mid]) {
right=mid-1;
} else {
left=mid+1;
}
}
//分析后半部分
else{
if(target<=nums[right]&&target>nums[mid]) {
left=mid+1;
} else {
right=mid-1;
}
}
}
return -1;
}
}
方法二:暴力法(一种不符合题意的解法)
//执行用时: 0 ms
//内存消耗: 40.8 MB
class Solution {
public int search(int[] nums, int target) {
for(int i=0;i<nums.length;i++){
if(nums[i]==target)
return i;
//注意:下面不可以写else{return -1},会报错。
}
return -1;
}
}
方法三:哈希表(一种不符合题意的解法)
//执行用时: 1 ms
//内存消耗: 41.3 MB
class Solution {
public int search(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
if(map.containsKey(target)) {
return map.get(target);
}
}
return -1;
}
}
34. 在排序 数组中查找元素的第一个和最后一个位置
(本题注意考虑当nums.length == 0 和 nums.length == 1的情况该怎么应对)
方法一:二分查找
//执行用时: 0 ms
//内存消耗: 44.5 MB
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = 0, right = nums.length - 1;
if(nums.length == 1 && nums[0] == target) return new int[]{0, 0};
while(left <= right) { //此处若没有等号,会得到错误的答案
int mid = left + (right - left)/2;
if(nums[mid] == target) {
int i = mid;
int j = mid;
while(i >= 0 && nums[i] == target) i--;
while(j <= nums.length - 1 && nums[j] == target) j++;
return new int[]{i + 1, j - 1};
}
else if(nums[mid] < target) left = mid + 1;
else right = mid - 1;
}
return new int[]{-1, -1};
}
}
方法二:双指针
//执行用时: 0 ms
//内存消耗: 44.5 MB
class Solution {
public int[] searchRange(int[] nums, int target) {
int left =0,right = nums.length-1;
while(left <= right){
while(left < right && nums[left] < target) {
left++;
}
while(left < right && nums[right] > target) {
right--;
}
if(nums[left] == target && nums[right] == target) {
return new int[]{left,right};
} else {
break;
}
}
return new int[]{-1,-1};
}
}
//执行用时: 0 ms
//内存消耗: 44.6 MB
class Solution {
public int[] searchRange(int[] nums, int target) {
int len = nums.length;
if(len == 1 && nums[0] == target) return new int[]{0,0};
int left = 0, right = len - 1;
while(left < right) {
while(left < right && nums[left] < target) {
left++;
}
while(left < right && nums[right] > target) {
right--;
}
if(nums[left] == target && nums[right] == target) {
return new int[]{left, right};
}
}
return new int[]{-1, -1};
}
}