前置知识
插入排序
- 插入排序
步骤:
1.从第一个元素开始,该元素可以认为已经被排序 2.取下一个元素tem,从已排序的元素序列从后往前扫描 3.如果该元素大于tem,则将该元素移到下一位 4.重复步骤3,直到找到已排序元素中小于等于tem的元素 5.tem插入到该元素的后面,如果已排序所有元素都大于tem,则将tem插入到下标为0的位置 6.重复步骤2~5
归并排序
归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法,归并排序对序列的元素进行逐层折半分组,然后从最小分组开始比较排序,合并成一个大的分组,逐层进行,最终所有的元素都是有序的 归并排序的核心:分治
归并排序与插入排序对比
基础的二路归并(c++)
//基础的二路归并
//核心思想:划分为两个子问题
//左边处理一下,得到左边的信息
//右边处理一下,得到右边的信息
//最后再处理一下,横跨左右两边的信息
void merge_sort(int *arr, int l, int r){
if(l >= r) return;
int mid = (l + r) / 2;
cout << endl;
cout << "sort : " << l << "<--->" << r << " : " << endl;
for(int i = l; i <= r; i++){
cout << arr[i] << " ";
}
cout << endl; //换行
//上面几行用来打印 方便观察
merge_sort(arr, l, mid);
merge_sort(mid + 1, r);
vector<int> temp(r - l + 1);
int k = 0, p1 = l, p2 = mid + 1;
//当左右两个区间还有元素的时候
while(p1 <= mid || p2 <= r){
//1. 右区间为空
//2. 左区间没空,并且,左区间的元素比较小
if((p2 > r) || (p1 <= mid && arr[p1] <= arr[p2])){
temp[k] = arr[p1];//最开始是把p1指向元素放进temp 0下标中
k++, p1++;
}else{//左区间空了,把右区间元素放进去
temp[k] = arr[p2];
k++, p2++;
}
}//右区间还有元素的话,继续把右区间的元素放进去
for(int i = l; i <= r; i++){
arr[i] = temp[i - l];
}//上面那两行相当于覆盖操作
//打印
for(int i = l; i <= r; i++){
cout << arr[i] << " ";
}
cout << arr[i] << " ";
return ;
}
int main(){
int a[10] = {1, 9, 0, 2, 5, 6, 2, 7, 1, 9};
merge_sort(a, 0, 9);
for(int i = 0; i < 10; i++){
cout << a[i] << " ";
}
return 0;
}
//归并排序稳定 时间复杂度:O(nlogn)
//空间复杂度:那个临时数组是在函数内部开辟的空间,属于栈上开辟的变量,先开辟n/2后再释放n/2,再开辟n/2,再释放... 最大的情况是开辟n的,所以空间复杂度为 O(n)
问题:电脑内存大小2GB,如何对一个40GB的文件进行排序?
- 分成20个数组,每个处理2GB的文件,最终得到20个有序数组
- 对文件的写入支持追加写,所以不需要临时变量来存
- 我们可以借助小顶堆加速,比如对20行文件以流的方式只读第一行文件
- 得到最小的文件后在后面继续追加,一直重复这个过程
- 时间复杂度:O(nlogn) * 20 + O(1) + O(n) O(1)因为堆是常量空间 O(n) 是扫一行 然后O(1)可以忽略掉,所以最后时间复杂度为:O(nlogn + n)
public class InsertSort {
private int[] array;
private int length;
public InsertSort(int[] array){
this.array = array;
this.length = array.length;
}
public void display(){
for(int a: array){
System.out.print(a+" ");
}
System.out.println();
}
public void doInsertSort(){
for(int index = 1; index<length; index++){
int temp = array[index];
int leftindex = index-1;
while(leftindex>=0 && array[leftindex]>temp){
array[leftindex+1] = array[leftindex];
leftindex--;
}
array[leftindex+1] = temp;
}
}
public static void main(String[] args){
int[] array = {38,65,97,76,13,27,49};
InsertSort is = new InsertSort(array);
System.out.println("排序前的数据为:");
is.display();
is.doInsertSort();
System.out.println("排序后的数据为:");
is.display();
}
}
public class MergeSort {
public void merge(int[] a,int left,int mid,int right){
int[] tmp=new int[a.length];
int p1=left,p2=mid+1,k=left;
while(p1<=mid && p2<=right){
if(a[p1]<=a[p2])
tmp[k++]=a[p1++];
else
tmp[k++]=a[p2++];
}
while(p1<=mid) tmp[k++]=a[p1++];
while(p2<=right) tmp[k++]=a[p2++];
for (int i = left; i <=right; i++)
a[i]=tmp[i];
}
public void mergeSort(int[] a,int start,int end){
if(start<end){
int mid=(start+end)/2;
mergeSort(a, start, mid);
mergeSort(a, mid+1, end);
merge(a, start, mid, end);
}
}
@Test
public void test(){
int[] a = { 49, 38, 65, 97, 76, 13, 27, 50 };
mergeSort(a, 0, a.length-1);
System.out.println("排好序的数组:");
for (int e : a)
System.out.print(e+" ");
}
}
经典题目
开胃菜
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if(list1 == null){
return list2;
}else if(list2 == null){
return list1;
} else if (list1.val < list2.val) {
list1.next = mergeTwoLists(list1.next, list2);
return list1;
} else {
list2.next = mergeTwoLists(list1, list2.next);
return list2;
}
}
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode hair = new ListNode(-1);
ListNode pre = hair;
while(list1 != null && list2 != null){
if(list1.val <= list2.val){
pre.next = list1;
list1 = list1.next;
}else{
pre.next = list2;
list2 = list2.next;
}
pre = pre.next;
}
pre.next = list1 == null ? list2 : list1;
return hair.next;
}
}
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int p1 = m-1;
int p2 = n-1;
int p = m+n-1;
while((p1>=0) && (p2>=0))
nums1[p--] = (nums1[p1]<nums2[p2]) ? nums2[p2--] : nums1[p1--];
System.arraycopy(nums2,0,nums1,0,p2+1);
}
}
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0];
}
});
int[][] res = new int[intervals.length][2];
int ind = -1;
for(int[] interval : intervals) {
if(ind == -1 || interval[0] > res[ind][1]) {
res[++ind] = interval;
}else {
res[ind][1] = Math.max(res[ind][1], interval[1]);
}
}
return Arrays.copyOf(res, ind + 1);
}
}
剑指offer51.数组中的逆序对(hard)
public class Num51 {
public int reversePairs(int[] nums) {
if(nums.length < 2) return 0;
return merge_sort(nums, 0, nums.length - 1);
}
private int merge_sort(int[] nums, int L, int R) {
if(L >= R) return 0;
int mid = L + ((R - L) >> 1), ans = 0;
ans = merge_sort(nums, L, mid) + merge_sort(nums, mid + 1, R);
int[] tmp = new int[R - L + 1];
int k = 0, p1 = L, p2 = mid + 1;
while(p1 <= mid || p2 <= R) {
if((p2 > R) || (p1 <= mid && nums[p1] <= nums[p2])) {
tmp[k++] = nums[p1++];
}else {
tmp[k++] = nums[p2++];
ans += (mid - p1 + 1);
}
}
for(int i = 0; i < tmp.length; i++) nums[i + L] = tmp[i];
return ans;
}
int[] nums, temp;
public int reversePairs1(int[] nums) {
this.nums = nums;
temp = new int[nums.length];
return mergeSort(0, nums.length - 1);
}
private int mergeSort(int L, int R) {
if(L >= R) return 0;
int m = (L + R) >> 1;
int res = mergeSort(L, m) + mergeSort(m + L, R);
int i = L, j = m + 1;
for(int k = L; k <= R; k++) {
temp[k] = nums[k];
}
for(int k = L; k <= R; k++) {
if(i == m + 1)
nums[k] = temp[j++];
else if(j == R + 1 || temp[i] <= temp[j])
nums[k] = temp[i++];
else {
nums[k] = temp[j++];
res += m - i + 1;
}
}
return res;
}
}
合并K个升序链表(hard)
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
public class Num23 {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) return null;
PriorityQueue<ListNode> q = new PriorityQueue<ListNode>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val - o2.val;
}
});
for(ListNode list : lists) if(list != null) q.offer(list);
ListNode ret = new ListNode(-1), p = ret;
while(!q.isEmpty()) {
ListNode cur = q.poll();
p.next = cur;
p = cur;
if(cur.next != null) q.offer(cur.next);
}
return ret.next;
}
}
排序链表
public class Num148 {
public ListNode sortList(ListNode head) {
int n = 0;
ListNode p = head;
while(p != null) {
p = p.next;
n++;
}
return merge_sort(head, n);
}
private ListNode merge_sort(ListNode head, int n) {
if(n <= 1) return head;
int l_cnt = n >> 1, r_cnt = n - l_cnt;
ListNode ret = new ListNode(-1), L = head, R = L, p = L;
for(int i = 0; i < l_cnt - 1; i++) p = p.next;
R = p.next;
p.next = null;
L = merge_sort(L, l_cnt);
R = merge_sort(R, r_cnt);
p = ret;
while(L != null || R != null) {
if((R == null) || (L != null && L.val <= R.val)) {
p.next = L;
p = L;
L = L.next;
}else {
p.next = R;
p = R;
R = R.next;
}
}
return ret.next;
}
}
两根搜索树中的所有元素
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
public class Num1305 {
public List<Integer> getAllElements(TreeNode root1, TreeNode root2){
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
List<Integer> res = new ArrayList<>();
inorder(root1, list1);
inorder(root2, list2);
int L = 0, R = 0;
while(L < list1.size() || R < list2.size()) {
if( (R >= list2.size()) || (L < list1.size() && list1.get(L) <= list2.get(R) )){
res.add(list1.get(L++));
}else {
res.add(list2.get(R++));
}
}
return res;
}
public void inorder(TreeNode root, List<Integer> list) {
if(root == null) return;
inorder(root.left, list);
list.add(root.val);
inorder(root.right, list);
}
List<Integer> ans;
public List<Integer> getAllElements1(TreeNode root1, TreeNode root2) {
ans = new ArrayList<>();
dfs(root1);
dfs(root2);
Collections.sort(ans);
return ans;
}
void dfs(TreeNode root) {
if (root == null) return;
dfs(root.left);
ans.add(root.val);
dfs(root.right);
}
}
区间和的个数(hard)
public class Num327 {
int lower, upper;
public int countRangeSum(int[] nums, int lower, int upper) {
this.lower = lower;
this.upper = upper;
long[] sum = new long[nums.length + 1];
sum[0] = 0;
for(int i = 0; i < nums.length; i++) sum[i + 1] = sum[i] + nums[i];
return merge_sort(sum, 0, sum.length - 1);
}
private int merge_sort(long[] nums, int L, int R) {
if(L >= R) return 0;
int mid = L + ((R - L) >> 1);
int ans = 0;
ans += merge_sort(nums, L, mid);
ans += merge_sort(nums, mid + 1, R);
ans += countTwoPart(nums, L, mid, mid + 1, R, lower, upper);
int k = 0, p1 = L, p2 = mid + 1;
long[] tmp = new long[R - L + 1];
while(p1 <= mid || p2 <= R) {
if((p2 > R) || (p1 <= mid && nums[p1] <= nums[p2])) {
tmp[k++] = nums[p1++];
}else {
tmp[k++] = nums[p2++];
}
}
for(int i = 0; i < tmp.length; i++) nums[i + L] = tmp[i];
return ans;
}
private int countTwoPart(long[] nums, int l1, int r1, int l2, int r2, int lower, int upper) {
int ans = 0;
for(int j = l2, k1 = l1, k2 = l1; j <= r2; j++) {
long a = nums[j] - upper;
long b = nums[j] - lower;
while(k1 <= r1 && nums[k1] < a) k1++;
while(k2 <= r1 && nums[k2] <= b) k2++;
ans += k2 - k1;
}
return ans;
}
}
计算右侧小于当前元素的个数(hard)
public class Num315 {
class Data{
int ind, val, cnt;
public Data(int ind, int val) {
this.ind = ind;
this.val = val;
this.cnt = 0;
}
}
public List<Integer> countSmaller(int[] nums) {
Data[] data = new Data[nums.length];
for(int i = 0; i < nums.length; i ++) {
data[i] = new Data(i, nums[i]);
}
merge_sort(data, 0, data.length - 1);
Arrays.sort(data, new Comparator<Data>() {
@Override
public int compare(Data o1, Data o2) {
return o1.ind - o2.ind;
}
});
List<Integer> res = new ArrayList<>();
for(Data datum : data) {
res.add(datum.cnt);
}
return res;
}
private void merge_sort(Data[] data, int L, int R) {
if(L >= R) return;
int mid = (L + R) >> 1;
merge_sort(data, L, mid);
merge_sort(data, mid + 1, R);
int k = 0, p1 = L, p2 = mid + 1;
Data[] tmp = new Data[R - L + 1];
while(p1 <= mid || p2 <= R) {
if((p2 > R) || (p1 <= mid && data[p1].val > data[p2].val)) {
data[p1].cnt += (R - p2 + 1);
tmp[k++] = data[p1++];
}else {
tmp[k++] = data[p2++];
}
}
for(int i = 0; i < tmp.length; i++) {
data[i + L] = tmp[i];
}
}
}
首个共同祖先
public class Num0408 {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null) return null;
if(root == p || root == q) return root;
TreeNode L = lowestCommonAncestor(root.left, p, q);
TreeNode R = lowestCommonAncestor(root.right, p, q);
if(L != null && R != null) return root;
if(L != null && R == null) return L;
return R;
}
}
层数最深叶子节点的和
public class Num1302 {
int ans, max_k;
public int deepestLeavesSum(TreeNode root) {
ans = 0;
max_k = 0;
getAns(root, 0);
return ans;
}
private void getAns(TreeNode root, int k) {
if(root == null) return;
if(k == max_k) ans += root.val;
else if(k > max_k) {
max_k = k;
ans = root.val;
}
getAns(root.left, k + 1);
getAns(root.right, k + 1);
}
}
|