关于排序的一些题目
关于排序的一些题目
1、合并区间
-
描述
-
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
-
示例
输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
-
-
解法
先将区间根据第一个元素排序,然后根据两个区间之间的交集关系,确定怎么往结果集里面放
-
源码
class Solution { public int[][] merge(int[][] intervals) { //排序 Arrays.sort(intervals,(o1, o2)->{ return o1[0]-o2[0]; }); int[][] res = new int[intervals.length][2]; res[0] = intervals[0]; int index = 0; //寻找可合并的情况 for(int i=1; i<intervals.length; i++){ //(1)、前者完全包含后者 //啥也不做 //(2)、两者有交集但是 前者尾部未包含后者尾部 if(res[index][1]>=intervals[i][0] && res[index][1]<=intervals[i][1]){ res[index] = new int[]{res[index][0],intervals[i][1]}; } //(3)、两者没有交集 else if(res[index][1] < intervals[i][0]){ //注意这里的 ++index,否则会将前面的值覆盖 res[++index] = intervals[i]; } } return Arrays.copyOfRange(res, 0, index+1); } }
2、数组的相对排序
-
描述
-
给你两个数组,arr1 和 arr2,arr2 中的元素各不相同,arr2 中的每个元素都出现在 arr1 中。
对 arr1 中的元素进行排序,使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。
数据约束: 1 <= arr1.length, arr2.length <= 1000 0 <= arr1[i], arr2[i] <= 1000 arr2 中的元素 arr2[i] 各不相同 arr2 中的每个元素 arr2[i] 都出现在 arr1 中 -
示例
输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6] 输出:[2,2,2,1,4,3,3,9,6,7,19]
-
-
解法
因为数据的范围不是太大,可以使用计数排序的方法,我这里用了count的二维数组,count[0]表示arr1里面出现的数字和次数,count[1]表示这个数字是否在arr2里面出现过,如果有的话置为1。
-
源码
class Solution { public int[] relativeSortArray(int[] arr1, int[] arr2) { int[] res = new int[arr1.length]; int[][] count = new int[2][1001]; //将arr1里面出现的数字和次数放入 count[0] 里面 for (int k : arr1) { count[0][k]++; } //结果数组res的下标 int index = 0; //遍历数组arr2,将出现的数字和count里面对应的次数放入res里面 for (int k : arr2) { //标记出现的数字 count[1][k] = 1; for (int j = 0; j < count[0][k]; j++) { res[index++] = k; } } //将未出现的数字按序放入res里面 for(int i=0; i<count[0].length; i++){ if((count[1][i]!=1) && (count[0][i]!=0)){ for(int j=0; j<count[0][i]; j++){ res[index++] = i; } } } return res; } }
3、数组中第 K 大的数
-
描述
-
给定整数数组
nums和整数k,请返回数组中第 **k**个最大的元素。请注意,你需要找的是数组排序后的第
k个最大的元素,而不是第k个不同的元素。 -
示例
输入: [3,2,1,5,6,4] 和 k = 2 输出: 5
-
-
解法
出题人的本意是想实现快排或者堆排。面试时也可能会让手撕快排或者优先队列,还是要掌握的。
-
源码
快排: class Solution { Random random = new Random(); public int findKthLargest(int[] nums, int k) { return quickSelect(nums, 0, nums.length - 1, nums.length - k); } public int quickSelect(int[] a, int l, int r, int index) { int q = randomPartition(a, l, r); if (q == index) { return a[q]; } else { return q < index ? quickSelect(a, q + 1, r, index) : quickSelect(a, l, q - 1, index); } } public int randomPartition(int[] a, int l, int r) { int i = random.nextInt(r - l + 1) + l; swap(a, i, r); return partition(a, l, r); } public int partition(int[] a, int l, int r) { int x = a[r], i = l - 1; for (int j = l; j < r; ++j) { if (a[j] <= x) { swap(a, ++i, j); } } swap(a, i + 1, r); return i + 1; } public void swap(int[] a, int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } } ============================================================ 堆排 class Solution { public int findKthLargest(int[] nums, int k) { int heapSize = nums.length; buildMaxHeap(nums, heapSize); for (int i = nums.length - 1; i >= nums.length - k + 1; --i) { swap(nums, 0, i); --heapSize; maxHeapify(nums, 0, heapSize); } return nums[0]; } public void buildMaxHeap(int[] a, int heapSize) { for (int i = heapSize / 2; i >= 0; --i) { maxHeapify(a, i, heapSize); } } public void maxHeapify(int[] a, int i, int heapSize) { int l = i * 2 + 1, r = i * 2 + 2, largest = i; if (l < heapSize && a[l] > a[largest]) { largest = l; } if (r < heapSize && a[r] > a[largest]) { largest = r; } if (largest != i) { swap(a, i, largest); maxHeapify(a, largest, heapSize); } } public void swap(int[] a, int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } }
4、链表排序
-
描述:
-
给你链表的头结点
head,请将其按 升序 排列并返回 排序后的链表 。 -
示例
输入:head = [4,2,1,3] 输出:[1,2,3,4]
-
-
解法:
使用归并的基本方法,涉及链表找中点和归并的基本知识
-
源码:
class Solution { public ListNode sortList(ListNode head) { //特殊情况 if(head == null) return null; //递归返回情况 if(head.next == null) return head; //找到中间节点 ListNode mid = findMid(head); ListNode h2 = mid.next; //断开原链表 mid.next = null; //排序合并 ListNode t1 = sortList(head); ListNode t2 = sortList(h2); return merge(t1,t2); } //快慢指针寻找链表中点 public ListNode findMid(ListNode head){ ListNode fast = head; ListNode slow = head; //偶数节点时,使用这个找到的是前面一个节点 while(fast.next != null){ if(fast.next.next != null) fast = fast.next.next; else break; if(slow.next != null) slow = slow.next; } return slow; } //合并有序链表 public ListNode merge(ListNode h1, ListNode h2){ //用来迭代的节点 ListNode temp = new ListNode(); //记录返回位置的节点 ListNode head = temp; //归并排序的基本方法 while(h1!=null && h2!=null){ if(h1.val <= h2.val){ temp.next = h1; h1 = h1.next; } else { temp.next = h2; h2 = h2.next; } temp = temp.next; } //归并:将后续节点加上来 if(h1 != null) temp.next=h1; if(h2 != null) temp.next=h2; return head.next; } }
5、合并排序链表
-
描述:
-
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
-
示例
输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释:链表数组如下: [ 1->4->5, 1->3->4, 2->6 ] 将它们合并到一个有序链表中得到。 1->1->2->3->4->4->5->6
-
-
解法:
借助上一题的链表合并,这题是很简单的,各个链表内部已经升序排好了,只需要合并即可。但是我使用的是顺序合并,时间复杂度略高。如果使用二分的方式,会快很多。
-
源码:
---------------顺序合并 101ms--------------- class Solution { public ListNode mergeKLists(ListNode[] lists) { if(lists==null || lists.length == 0) return null; for(int i=1; i<lists.length; i++){ ListNode temp = merge(lists[i-1],lists[i]); lists[i] = temp; } return lists[lists.length-1]; } //合并有序链表 public ListNode merge(ListNode h1, ListNode h2){ ListNode temp = new ListNode(); ListNode head = temp; while(h1!=null && h2!=null){ if(h1.val <= h2.val){ temp.next = h1; h1 = h1.next; } else { temp.next = h2; h2 = h2.next; } temp = temp.next; } if(h1 != null) temp.next=h1; if(h2 != null) temp.next=h2; return head.next; } } -----------二分递归 1ms范例----------- class Solution { public ListNode mergeKLists(ListNode[] lists) { return marge(lists, 0, lists.length - 1); } public ListNode marge(ListNode[] lists, int l, int r){ if(l > r) return null; int mid = l + (r - l) / 2; if(l == r) return lists[l]; return mergeTwoLists(marge(lists, l, mid), marge(lists, mid + 1, r)); } public ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode res = new ListNode(0); ListNode cur = res; while(l1 != null && l2 != null){ if(l1.val <= l2.val){ cur.next = l1; l1 = l1.next; }else{ cur.next = l2; l2 = l2.next; } cur = cur.next; } cur.next = l1 == null ? l2 : l1; return res.next; } }

浙公网安备 33010602011771号