基础算法模板题(一)—— 排序

快速排序

【题目描述】

在这里插入图片描述

AcWing 785. 快速排序

【思路】

  1. 确定分界点x,x可取 x[l],x[r]或者x[(l+r)/2]
  2. 根据分界点调整区间,以分界点为轴,左边的都不大于x,右边的都不小于x。
  3. 递归处理
    模板
 public static void quick_sort(int l, int r, int q[]){
        //区间为空时返回
        if( l > r) return;
        int j = partition(l, r, q);
        //3、递归处理 划分为[l,j-1]和[j+1,r]两个区间
        quick_sort(l, j - 1 , q);
        quick_sort(j + 1, r, q);
    }
    //返回分界点元素应该放置的位置
    public static int partition(int l, int r, int q[]){
        //1、确定分界点x
        int i = l, j = r, x = q[l];
        //2、根据分界点调整区间
        while( i < j){
            while( i < j && q[j] >= x) j --;
            while( i < j && q[i] <= x) i ++;
            if( i < j){//交换
                int tmp = q[i];
                q[i] = q[j];
                q[j] = tmp;
            }
        }
        //i指针的位置即为分界点元素应该放置的位置
        a[l] = a[i];
        a[i] = x;
        return i;
        
    }

第k个数

【题目描述】
在这里插入图片描述

AcWing 786. 第k个数

【思路】

应用快排思想

 /**
     * l 区间左端点
     * r 区间右端点
     * k [l,r]区间第k小
     */
    public static int selectK(int l, int r, int q[], int k){
        if( l == r) return q[l];
        int i = partition(l, r, q);
        int j = i - l + 1; //j为q[i]元素在新划定区间[l,r]的排名
        if( j >= k)  return selectK(l, i, q, k);
        else return selectK(i + 1 , r, q, k - j);
        
    }
    public static int partition(int l, int r, int []q){
        int i = l, j = r, x = q[l];
        while( i < j){
            while( i < j && q[j] >= x ) j--;
            while( i < j && q[i] <= x ) i++;
            if( i < j){
                int tmp = q[i];
                q[i] = q[j];
                q[j] = tmp;
            }
        }
        q[l] = q[i];
        q[i] = x;
        return i;
    }

归并排序

【题目描述】
在这里插入图片描述

AcWing 787. 归并排序

【思路】
1 、确定分界下标,mid = (l+r)/2
2、递归求解子问题
3、 合并子问题

public static void mergeSort(int l, int r , int [] q){
        //一个元素时自然有序
        if( l >= r ) return;
        int mid = l + r >> 1;
        mergeSort(l, mid, q);   //[l, mid]
        mergeSort(mid + 1, r, q); //[mid + 1, r]
        //合并有序区间
        merge(l, mid, r, q);
    }
public static void merge(int l, int mid, int r, int [] q){
        int i = l, j = mid + 1, k = 0;
        //辅助数组
        int b[] = new int[ r - l + 1];
        while( i <= mid && j <= r){
            while( i <= mid && q[i] <= q[j] ) b[k++] = q[i++];
            while( j <= r && q[j] <q[i] ) b[k++] = q[j++];
        }
        while( i <= mid ) b[k++] = q[i++];
        while( j <= r ) b[k++]  = q[j++];
        for(int p = l,m = 0; p <= r; p ++, m ++) q[p] = b[m]; 
        
    }

逆序对的数量

【题目描述】
在这里插入图片描述

AcWing 788. 逆序对的数量

【思路】

归并排序思想

import java.io.*;
public class Main{
    static int N = 100010;
    static int q[] =new int[N];
    static long cnt ;
    public static void mergeSort(int l, int r, int []q){
        if( l >= r) return;
        int mid = (l+r)>>1;
        mergeSort(l, mid, q);
        mergeSort(mid + 1, r, q);
        merge(l, mid, r, q);
    }
    public static void merge(int l, int mid, int r, int []q){
        int i = l, j = mid + 1, k = 0;
        int b [] = new int[ r - l + 1];
        while( i <= mid && j <= r){
            while( i <= mid && q[i] <= q[j]) b[k++] = q[i++];
            //前大后小即为逆序对
            while( j <= r && q[i] > q[j] ) {
                b[k++] = q[j++];
                cnt += mid - i + 1;
            }
        }
        while( i <= mid) b[k++] = q[i++];
        while( j <= r) b[k++] =q[j++];
        for(int t = 0; l <= r; l++, t++) q[l] = b[t];
    }
    public static void main(String args[]) throws Exception{
        BufferedReader bf =new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(bf.readLine());
        String strArr [] = bf.readLine().split(" ");
        for(int i = 0; i < n; i++) q[i] = Integer.parseInt(strArr[i]);
        mergeSort(0, n-1, q);
        System.out.println(cnt);
    }
}

Java中排序结构的定义

// 快速排序
import java.util.Scanner;
import java.util.Arrays;

class Cmp implements Comparable<Cmp>{
    int num, sum;
    public Cmp(int n, int s){
        num = n;
        sum = s;
    }
    public int compareTo(Cmp o){
        if(this.sum == o.sum){
            return Integer.compare(this.num, o.num);
        }
        return Integer.compare(this.sum, o.sum);
    }
}
class Main{
    static int N = 1000010;
    static Cmp f[] = new Cmp[N];
    public static void main(String args[]){
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt(), m = reader.nextInt();
        // 数位分解
        for(int i = 1; i <= n; i ++){
            int x = i, res = 0;
            while(x > 0){
                res += x % 10;
                x /= 10;
            }
            f[i] = new Cmp(i, res);
        }
        // 返回值为int类型,大于0表示正序,小于0表示逆序
        Arrays.sort(f, 1, n + 1);
        System.out.println(f[m].num);
        
    }
}

差分
4655. 重新排序

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int N = 100010;
    static long[] arr = new long[N];
    static long[] cnt = new long[N];
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
       
        for (int i = 1; i <= n; ++i) {
            arr[i] = sc.nextLong();
        }
        int m = sc.nextInt();
        while (m-- > 0) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            // 构造一维差分数组
            cnt[l]++;
            cnt[r + 1]--;
        }
        // 差分数组恢复为统计次数
        for (int i = 1; i <= n; ++i) {
            cnt[i] += cnt[i - 1];
        }
        // 排序前数组的和
        long sumA = 0;
        for (int i = 1; i <= n; ++i) {
            sumA += cnt[i] * arr[i];
        }
        long sumB = 0;
        Arrays.sort(arr, 1, n + 1);
        Arrays.sort(cnt, 1, n + 1);
        // 排序后数组的和
        for (int i = 1; i <= n; ++i) {
            sumB += cnt[i] * arr[i];
        }
        System.out.println(sumB - sumA);
    }
}

多路归并

1262. 鱼塘钓鱼

1262. 鱼塘钓鱼
在这里插入图片描述

import java.util.Scanner;
import java.util.PriorityQueue;
class Main{
    static int N = 110;
    static int []f = new int[N], df = new int[N], mt = new int[N];
    public static void main(String agrs[]){
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt();
        for(int i = 1; i <= n; i ++){
            f[i] = reader.nextInt();
        }
        for(int i = 1; i <= n; i ++){
            df[i] = reader.nextInt();
        }
        for(int i = 1; i < n; i ++){
            mt[i] = reader.nextInt();
        }
        int T = reader.nextInt();
        int ans = 0;
        // 优先队列维护一个大根堆
        PriorityQueue<Integer> pd = new PriorityQueue<>((o1, o2)->o2 - o1);
        for(int i = 1; i <= n; i ++){ // 枚举最远能到到的鱼塘
            int t = T, res = 0;
            for(int j = 0; j < i; j ++){ // 减去转移的时间,得到完全用于钓鱼的时间
                t -= mt[j];
            }
            for(int j = 1; j <= i; j ++){
                for(int k = f[j]; k > 0; k -= df[j]){
                    pd.add(k);
                }
            }
            //  获取不超过t个的前几个数
            while(t > 0&& !pd.isEmpty()){
                res += pd.poll();
                t --;
            }
            ans = Math.max(res, ans);
            // 新的一轮比较
            pd.clear();
            
        }
        System.out.println(ans);
    }
}

4656. 技能升级

在这里插入图片描述

4656. 技能升级

朴素做法
每个技能构成一个等差数列,对所有的等差数列进行排序选择前m大的数即可。
只能过一半的数据。

/*
A较大 B较小
A   10  9   8
B   -5  -2  -1
cnt 2   5   8
1   10  
    5   9   8
2       9   
    5   7   8
3           8
    5   7   7
4           7
    5   7   6
5       7
    5   5   6
6           6
    5   5   5
10 + 9 + 8 + 7 + 7 + 6

10 5 0
9 7 5 3 1 0
8 7 6 5 4 3 2 1
A - B*t
*/

import java.util.Scanner;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Collections;
class Main{
    static int N = 100010;
    static int C = 10000010;
    static int []A = new int[N];
    static int []B = new int[N];
    static Integer []s = new Integer[C];
    public static void main(String agrs[]){
        Scanner reader = new Scanner(System.in);
        long n = reader.nextLong(), m = reader.nextLong();
        for(int i = 1; i <= n; i ++){
            A[i] = reader.nextInt();
            B[i] = reader.nextInt();
        }
        int p = 0;
        for(int i = 1; i <= n; i ++){
            int j = A[i];
            for(; j> B[i]; j -= B[i]){
                s[++p] = j;   
            }
            if(j > 0){
                s[++p] = j;
            }
            
        }
        // for(int i = 1; i <= p; i ++){
        //      System.out.print(s[i] + " ");
        // }
        // System.out.println(p);
        // Arrays.sort(s, 1, p + 1, Collections.reverseOrder());
        // // 使用自定义比较器对象进行降序排序
        Arrays.sort(s, 1, p + 1, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1); // 降序排序
            }
        });
        long ans = 0;
        for(int i = 1; i <= m; i ++){
            ans += s[i];
        }
        System.out.println(ans);
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值