文章目录
Leetcode 21.合并两个有序链表 / BM4.合并两个排序的链表
1.问题描述
2.解决方案
解法一:迭代法顺序合并(重点关注!!)
思路核心点就是设置一个哨兵节点和前继节点的思路!
import java.util.*;
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
//1.虚拟头节点和前继节点
ListNode preHead = new ListNode(-1);
ListNode prev = preHead;
//2.都不为空进入
while(list1!=null&&list2!=null){
if(list1.val<list2.val){
prev.next=list1;
prev=list1;
list1=list1.next;
}else{
prev.next=list2;
prev=list2;
list2=list2.next;
}
}
//3.合并剩余的链表
if(list1==null){
prev.next=list2;
}else{
prev.next=list1;
}
return preHead.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;
}
}
}
Leetcode 23.合并K个升序链表 / BM5.合并k个已排序的链表
1.问题描述
2.解决方案
解法一:归并法顺序合并(重点关注!!)
1.最关键的就是分治递归的一个思想,divideMerge要返回Merge(list1,list2)的结果,那么list1,list2又是divideMerge处理的结果。
2.最终的递归出口其实是要么为null,要么left==right返回一个链表,然后Merge两个链表,并且作为divideMerge的返回,然后再一层一层往上Merge。
3.体会思想很重要。
import java.util.ArrayList;
public class Solution {
//两个链表合并函数
public ListNode Merge(ListNode list1, ListNode list2) {
//一个已经为空了,直接返回另一个
if(list1 == null)
return list2;
if(list2 == null)
return list1;
//加一个表头
ListNode head = new ListNode(0);
ListNode cur = head;
//两个链表都要不为空
while(list1 != null && list2 != null){
//取较小值的节点
if(list1.val <= list2.val){
cur.next = list1;
//只移动取值的指针
list1 = list1.next;
}else{
cur.next = list2;
//只移动取值的指针
list2 = list2.next;
}
//指针后移
cur = cur.next;
}
//哪个链表还有剩,直接连在后面
if(list1 != null)
cur.next = list1;
else
cur.next = list2;
//返回值去掉表头
return head.next;
}
//划分合并区间函数
ListNode divideMerge(ArrayList<ListNode> lists, int left, int right){
//终极递归出口:返回null
if(left > right) return null;
//终极递归出口:返回一个链表
if(left == right) return lists.get(left);
//从中间分成两段,再将合并好的两段合并
int mid = (left + right) / 2;
return Merge(divideMerge(lists, left, mid), divideMerge(lists, mid + 1, right));
}
public ListNode mergeKLists(ArrayList<ListNode> lists) {
//k个链表归并排序
return divideMerge(lists, 0, lists.size() - 1);
}
}
解法二:优先队列 or 辅助数组排序构建新链表
优先队列,把所有链表构造为优先队列,然后从优先队列取出来构造新链表
import java.util.*;
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode mergeKLists(ArrayList<ListNode> lists) {
//1.先注入优先队列
PriorityQueue<Interger> queue = new PriorityQueue<>();
for(ListNode head : lists){
while(head!=null){
queue.add(head.val);
head = head.next;
}
}
//2.然后从优先队列里面一直取数,生成链表
ListNode dummyHead = new ListNode(-1);
ListNode t = dummyHead;
while(queue.size()>0){
t.next = new ListNode(queue.remove());
t = t.next;
}
return dummyHead.next;
}
}
先把所有链表元素,放到数组中,然后排序,然后构造新链表
import java.util.*;
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode mergeKLists(ArrayList<ListNode> lists) {
//1.把所有链表数据放到list中
List<Integer> list = new ArrayList<>();
for(ListNode head : lists){
while(head!=null){
list.add(head.val);
head = head.next;
}
}
//2.排序
Collections.sort(list);
//3.然后用排序后的list构造新链表
ListNode dummyHead = new ListNode(-1);
ListNode t = dummyHead;
for(int a : list){
t.next = new ListNode(a);
t = t.next;
}
return dummyHead.next;
}
}
Leetcode 378.有序矩阵中第 K 小的元素
1.问题描述
2.解决方案
解法一:归并法顺序合并(重点关注!!)
主要思路就是:
1.优先队列存一个Node,里面包含矩阵的值val和坐标(i,j),然后根据val构建小根堆。
2.每次弹出最小的,然后把这一行后一个元素放到堆中,作为候选的Node。
3.然后弹出第k个就结束。
class Solution {
class Node{
//矩阵里面的值
int val;
//坐标(i,j)
int i, j;
Node(int val, int i, int j){
this.val = val;
this.i = i;
this.j = j;
}
}
public int kthSmallest(int[][] matrix, int k) {
//按照Node的val从小到大 小根堆
int len = matrix.length;
PriorityQueue<Node> queue = new PriorityQueue<>((t1, t2)->(t1.val - t2.val));
//把第一列候选最小值加入堆排序
for(int i=0;i<len;i++){
queue.add(new Node(matrix[i][0], i, 0));
}
//从堆中取最小,如果一个节点被删除,然后把这个节点同行的后一个节点加入堆
int cnt = 0;
Node t = null;
while(cnt!=k){
//弹出一个元素 cnt++
t = queue.remove();
cnt++;
//如果某一行元素弹没了 就不加入了
if(t.j+1<=len-1){
queue.add(new Node(matrix[t.i][t.j+1], t.i, t.j+1));
}
}
return t.val;
}
}
解法二:优先队列 or 辅助数组排序取值
class Solution {
public int kthSmallest(int[][] matrix, int k) {
//1.把二维数组全部放到一维数组
List<Integer> list = new ArrayList<>();
int len = matrix.length;
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
list.add(matrix[i][j]);
}
}
//2.排序然后取第k小的数据
Collections.sort(list);
return list.get(k-1);
}
}
解法三:二分法
对于求中间数mid的值有两种方法,对于第一种过不了这个样例,因为-5 -4 求出来一直是-4,
而第二种方法 -5 -4求出来是-5就可以过
//int mid = (left+right)/2;
int mid = left + ((right - left) >> 1);
class Solution {
//1:在左边 2:在右边 3:就是mid但是有可能mid不在矩阵中,所以相当于在mid左边了
public int check(int[][] matrix, int len, int mid, int k){
int i = len-1;
int j = 0;
int num = 0;
while(i>=0 && j<=len-1){
if(matrix[i][j]<=mid){
//说明这一列都小于等于mid 都算上
num += i+1;
j++;
continue;
}
if(matrix[i][j]>mid){
//这一列往上找
i--;
continue;
}
}
//小于等于mid的数字个数是num
if(num>k) return 1;
if(num<k) return 2;
if(num==k) return 3;
//编译出口 不可能从这走
return -1;
}
public int kthSmallest(int[][] matrix, int k) {
int len = matrix.length;
int left = matrix[0][0];
int right = matrix[len-1][len-1];
while(left<right){
//int mid = (left+right)/2;
int mid = left + ((right - left) >> 1);
int flag = check(matrix, len, mid, k);
if(flag==1||flag==3) right=mid;
if(flag==2) left=mid+1;
}
return right;
}
}
Leetcode 373.查找和最小的 K 对数
1.问题描述
2.解决方案
解法一:归并最小堆排序(重点关注!!)
1.先把num1.0.1…len-1 和 num2.0 组合起来加到堆中。
2.取最小t,然后加入结果集。
3.t的nums1_index不变 t.nums2_index+1加入堆。
class Solution {
class Node{
int nums1_index;
int nums2_index;
Node(int nums1_index, int nums2_index){
this.nums1_index = nums1_index;
this.nums2_index = nums2_index;
}
}
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
//按照数字对的和从小到大
PriorityQueue<Node> queue = new PriorityQueue<>((o1, o2)->((nums1[o1.nums1_index]+nums2[o1.nums2_index])-(nums1[o2.nums1_index]+nums2[o2.nums2_index])));
//先把num1.0.1..len-1 和 num2.0 组合起来加到堆中
for(int i=0;i<nums1.length;i++){
queue.add(new Node(i, 0));
}
//取最小数对,加入结果集
List<List<Integer>> ans = new ArrayList<>();
int cnt = 0;
Node t = null;
while(cnt<k&&queue.size()>0){
//取最小 然后加入结果集
t = queue.remove();
ans.add(Arrays.asList(new Integer[]{nums1[t.nums1_index], nums2[t.nums2_index]}));
cnt++;
//t的nums1_index不变 t.nums2_index+1加入堆
if(t.nums2_index+1<=nums2.length-1){
queue.add(new Node(t.nums1_index, t.nums2_index+1));
}
}
return ans;
}
}
解法二:二分查找
没看懂
class Solution {
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
int m = nums1.length;
int n = nums2.length;
/*二分查找第 k 小的数对和的大小*/
int left = nums1[0] + nums2[0];
int right = nums1[m - 1] + nums2[n - 1];
int pairSum = right;
while (left <= right) {
int mid = left + ((right - left) >> 1);
long cnt = 0;
int start = 0;
int end = n - 1;
while (start < m && end >= 0) {
if (nums1[start] + nums2[end] > mid) {
end--;
} else {
cnt += end + 1;
start++;
}
}
if (cnt < k) {
left = mid + 1;
} else {
pairSum = mid;
right = mid - 1;
}
}
List<List<Integer>> ans = new ArrayList<>();
int pos = n - 1;
/*找到小于目标值 pairSum 的数对*/
for (int i = 0; i < m; i++) {
while (pos >= 0 && nums1[i] + nums2[pos] >= pairSum) {
pos--;
}
for (int j = 0; j <= pos && k > 0; j++, k--) {
List<Integer> list = new ArrayList<>();
list.add(nums1[i]);
list.add(nums2[j]);
ans.add(list);
}
}
/*找到等于目标值 pairSum 的数对*/
pos = n - 1;
for (int i = 0; i < m && k > 0; i++) {
int start1 = i;
while (i < m - 1 && nums1[i] == nums1[i + 1]) {
i++;
}
while (pos >= 0 && nums1[i] + nums2[pos] > pairSum) {
pos--;
}
int start2 = pos;
while (pos > 0 && nums2[pos] == nums2[pos - 1]) {
pos--;
}
if (nums1[i] + nums2[pos] != pairSum) {
continue;
}
int count = (int) Math.min(k, (long) (i - start1 + 1) * (start2 - pos + 1));
for (int j = 0; j < count && k > 0; j++, k--) {
List<Integer> list = new ArrayList<>();
list.add(nums1[i]);
list.add(nums2[pos]);
ans.add(list);
}
}
return ans;
}
}
解法三:全量排序
把所有数字对都放到list中,然后按照两个的和排序,取出前三对。
class Solution {
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
List<List<Integer>> ans = new ArrayList<>();
for(int i=0;i<nums1.length;i++){
for(int j=0;j<nums2.length;j++){
List<Integer> list = new ArrayList<>();
list.add(nums1[i]);
list.add(nums2[j]);
ans.add(list);
}
}
Collections.sort(ans, (t1, t2) -> (t1.get(0)+t1.get(1)) - (t2.get(0)+t2.get(1)));
List<List<Integer>> result = new ArrayList<>();
for(int i=0;i<k&&i<=ans.size()-1;i++) result.add(ans.get(i));
return result;
}
}