基础算法(java)

目录​​​​​​​

1.快速排序

2.归并排序

3.整数二分(两个模版)

4.浮点数二分模版

5.高精度计算​​​​​​​

1)加法

2)减法

3)乘法

4)除法

6.前缀和与差分

1)一维数组前缀和

2)二维前缀和

3)差分

4)差分矩阵

7.双指针算法

8.位运算

1)获取数字 n的二进制的第 k位是多少

2)lowBit

9.离散化

10.区间合并


1.快速排序

import java.util.*;

public class Main{
    private static int N = 100010;
    private static int[] q = new int[N];
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        for(int i = 0; i <n; i++){
            q[i] = scanner.nextInt();
        }
        int l = 0, r = n - 1;
        quicksort(q, l, r);
        for(int i = 0; i < n; i++){
            System.out.print(q[i] + " ");
        }
        
    }

    //快排模版
    public static void quicksort(int[] q, int l, int r){
        if (l >= r){
            return;
        }
        int x = q[l + r >> 1];
        int i = l - 1;
        int j = r + 1;
        
        while(i < j){
            do i ++; while (q[i] < x);//找到第一个大于等于x的数,不能取=,因为第一个数可能比后面所有数都大,必须交换第一个数
            do j --; while (q[j] > x);//找到第一个小于等于x的数,不能取=
            // 交换两个数,保证i左边数小于等于x,j右边数大于等于x
            if(i < j){
                int tmp = q[i];
                q[i] = q[j];
                q[j] = tmp;
            }
        }
        quicksort(q, l ,j); // j有可能小于i,所以取j
        quicksort(q, j + 1, r);
    }
}

2.归并排序

import java.util.*;

public class Main{
    private static int N = 100010;
    private static int[] q = new int[N];
    private static int[] tmp = new int[N];
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        for(int i = 0; i < n; i ++){
            q[i] = scan.nextInt();
        }
        int l = 0, r = n - 1;
        merge_sort(q, l, r);
        for(int i = 0; i < n; i++){
            System.out.print(q[i] + " ");
        }
    }

    //归并模版
    public static void merge_sort(int[] q, int l, int r){
        if(l >= r) return;
        int mid = l + r >> 1;
        merge_sort(q, l, mid);
        merge_sort(q, mid + 1, r);
        
        int i = l, j = mid + 1, id = 0;
        while(i <= mid && j <= r){
            if(q[i] <= q[j]) tmp[id ++] = q[i ++];
            else tmp[id ++] = q[j ++];
        }
        while(i <= mid) tmp[id ++] = q[i ++]; 
        while(j <= r) tmp[id ++] = q[j ++];
        for(i = l, id = 0; i <= r; i ++, id ++) q[i] = tmp[id];
    }
}

3.整数二分(两个模版)

// 区间[l, r]被划分成 [l, mid] 和 [mid+1, r]时使用
int bsearch_1(int l, int r) {
    while (l < r) {
        int mid = l + r >> 1;
        if (check[mid)  // check() 判断 mid是否满足性质
            r = mid; 
        else
            l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成 [l, mid-1] 和 [mid, r]时使用
int bsearch_2(int l, int r) {
    while (l < r) {
        int mid = l + r + 1 >> 2;   // 注意
        if (check[mid)  // check() 判断 mid是否满足性质
            l = mid;
        else
            r = mid - 1;

    }
    return l;
}
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int q = scan.nextInt();
        
        int arr[] = new int[n]; 
        for(int i = 0; i < n; i++){
            arr[i] = scan.nextInt();
        }
        
        while(q-- != 0){
            int target = scan.nextInt();
            int l = 0, r = n - 1;
            while(l < r){
                int mid = l + r >> 1;
                if(arr[mid] >= target) r = mid;
                else l = mid + 1;
            }
            if(arr[l] != target){
                System.out.println("-1 -1");
            }else{
                System.out.print(l + " ");
                int i = 0, j = n - 1;
                while(i < j){
                    int mid = i + j + 1 >>1;
                    if(arr[mid] <= target) i = mid;
                    else j = mid - 1;
                }
                System.out.println(j);
            }
            
        }
        
    }
        
}

4.浮点数二分模版


​​​​​​​​​​

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        double target = scan.nextDouble();
        
        double l = -10000, r = 10000;
        
        while(r - l > 1e-8){
            double mid = (l + r) / 2;
            if(mid * mid * mid >= target) r = mid;
            else l = mid;
        }
        
        System.out.println(String.format("%.6f", l));
    }
}

ps:模版
double bsearch(double l, double r) {
    const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求, 一般比所求精度高 2
    while (r - l > eps) {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

5.高精度计算​​​​​​​

1)加法

import java.util.*;
public class Main{

    public static String sum(List<Integer> a,List<Integer> b) {
        int[] c = new int[100010];
        int t = 0,i;
        for(i = 0;i < a.size() || i < b.size(); i ++) {
            if(i < a.size()) c[i] = t += a.get(i);
            if(i < b.size()) c[i] = t += b.get(i);
            c[i] = t % 10;
            t = t/10;
        }
        if(t > 0) c[i] = t;
        while(i >= 1 && c[i] == 0) i --;
        StringBuilder stb = new StringBuilder();
        for(int j = i; j >= 0; j --) {
            stb.append(c[j]);
        }
        return stb.toString();
    }

    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        String a = sc.nextLine();
        String b = sc.nextLine();
        List<Integer> A =new ArrayList<>(a.length());
        List<Integer> B =new ArrayList<>(b.length());
        for(int i = a.length() - 1;i >= 0;i --) {
            A.add(a.charAt(i) - '0');
        }
        for(int i = b.length() - 1;i >= 0;i --) {
            B.add(b.charAt(i) - '0');
        }

        System.out.print(sum(A,B));

    }
}

2)减法

import java.util.*;

public class Main {
	// 判断是否有 A >= B
    public static boolean cmp(List<Integer> A, List<Integer> B) {
        if (A.size() != B.size()) return A.size() > B.size();
        for (int i = A.size() - 1; i >= 0; i--) {
            if (A.get(i) != B.get(i)) return A.get(i) > B.get(i);
        }
        return true;
    }
    
    public static List<Integer> sub(List<Integer> A, List<Integer> B) {
        List<Integer> C = new ArrayList();
        
        int t = 0; // 差
        for (int i = 0; i < A.size(); i++) {
            t += A.get(i);
            if (i < B.size()) t -= B.get(i);
            C.add((t + 10) % 10); // t >= 0: t; t < 0 : t + 10(借位)
            if (t < 0) t = -1;
            else t = 0;
        }
        while(C.size() > 1 && C.get(C.size() - 1) == 0) C.remove(C.size() - 1); // 删除前导0
        
        return C;
    }
    
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String a = scan.nextLine();
        String b = scan.nextLine();
        
        List<Integer> A = new ArrayList(), B = new ArrayList();
        for (int i = a.length() - 1; i >= 0; i--) A.add(a.charAt(i) - '0');
        for (int i = b.length() - 1; i >= 0; i--) B.add(b.charAt(i) - '0');
        
        if (cmp(A, B)) {
            List<Integer> C = sub(A, B);
            for (int i = C.size() - 1; i >= 0; i--) System.out.print(C.get(i));
        }
        else {
            System.out.print("-");
            List<Integer> C = sub(B, A);
            for (int i = C.size() - 1; i >= 0; i--) System.out.print(C.get(i));
        }
    }
}

3)乘法

import java.util.*;

public class Main{
    
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        String a = scan.nextLine();
        int b = scan.nextInt();
        List<Integer> A = new ArrayList<>();
        for(int i = a.length() - 1; i >= 0; i--) A.add(a.charAt(i) - '0');
        List<Integer> C = sub(A, b);
        for(int i = C.size() - 1; i >= 0; i--) System.out.print(C.get(i));
    }
    
    public static List<Integer> sub(List<Integer> A, int b){
        int t = 0;
        for(int i = 0; i < A.size(); i++){
            t += A.get(i) * b;
            A.set(i, t % 10);
            t = t / 10;
        }
        if(t != 0) A.add(t);
        while(A.size() > 1 && A.get(A.size() - 1) == 0) A.remove(A.size() - 1);
        return A;
    }
    
}

4)除法

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        String a =scan.next();
        int b = scan.nextInt();
        int[] A = new int[a.length()];
        //除法不需要逆向输入
        for(int i = 0; i < a.length(); i ++){
            A[i] = a.charAt(i) - '0';
        }
        div(A, b);
    }
    
    public static void div(int[] a, int b){
        int i;
        int r = 0;
        int[] c = new int[a.length + 1];
        for(i = 0; i < a.length; i++){
            r = r * 10 + a[i];
            c[i] = r / b;
            r %= b;
        }
        int len = i;
        i = 0;
        while(c[i] == 0 && i < a.length - 1 ) i ++;  //去前导0;
        for(int j = i; j < len; j++){
            System.out.print(c[j]);
        }
        System.out.println();
        System.out.print(r);
    }
    
}

6.前缀和与差分

1)一维数组前缀和

 

        
// 求a[]数组的前缀和:
for(int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i - 1]; // 前缀和下标[1, n],数组a下标[0, n - 1]
sum[l, r] = s[r] - s[l - 1] // 第l个数 到 第r个数 的和


import java.util.*;

public class Main {
    private static int N = 100010;  // 定义数组大小, 防止越界

    public static void main(String[] args) {
        // 初始化输入值
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        int[] arr = new int[N];
        // 注意这里是从 1开始的
        for (int i = 1; i <= n; i++)     
            arr[i] = in.nextInt();

        // s[i]代表 arr的前 i项和
        int s[] = new int[N];   
        s[0] = 0;   
        // 计算出 s[i]
        for (int i = 1; i <= n; i++)
            s[i] = s[i - 1] + arr[i];     // 注意运算方式

        // 循环输出
        while (m-- > 0) {
              int l = in.nextInt();
              int r = in.nextInt();
              System.out.println(s[r] - s[l - 1]);  // 关键
        }
    }
}

2)二维前缀和

import java.util.*;

 public class Main{
     
     public static void main(String[] args){
         Scanner scan = new Scanner(System.in);
         int n = scan.nextInt();
         int m = scan.nextInt();
         int q = scan.nextInt();
         
         int[][] arr = new int[n + 1][m + 1];
         for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                arr[i][j] = scan.nextInt();
             }
         }
         
         int[][] s = new int[n + 1][m + 1];
         for(int i = 1; i <= n; i++){
             for(int j = 1; j <= m; j++){
                 s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + arr[i][j];
             }
         }
         
         while(q -- > 0){
            int x1 = scan.nextInt();
            int y1 = scan.nextInt();
            int x2 = scan.nextInt();
            int y2 = scan.nextInt();
            
            System.out.println(s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
         }
         
     }
     
 }
// 求a[][]数组左上角元素的和:
for (int i = 1; i <= n; i++)
	for (int j = 1; j <= m;j++) 
		s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i - 1][j - 1];
int x1, y1, x2, y2;
s[x2][y2] - s[x1 - 1][y2] - s[x1][y1 - 1] + s[x1 - 1][y1 - 1] // 矩形区域和

3)差分

差分就是前缀和的逆运算

import java.util.*;

public class Main{
    
    private static int N = 100010;
    
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int m = scan.nextInt();
        
        int[] a = new int[N];
        for(int i = 1; i <= n; i++) a[i] = scan.nextInt();
        
        int[] b = new int[N];
        for(int i = 1; i <= n; i++) b[i] = a[i] - a[i - 1];
        
        while(m -- > 0){
            int l = scan.nextInt();
            int r = scan.nextInt();
            int c = scan.nextInt();
            b[l] += c;
            b[r + 1] -= c;
        }
        
        for(int i = 1; i <= n; i++) b[i] += b[i - 1];
        for(int i = 1; i <= n; i++) System.out.print(b[i]+" ");
        
    }
    
}
//1:初始化差分数组b[]
        int[] b = new int[N];                               
        for(int i = 1 ; i <= n ; i++) b[i] = s[i] - s[i-1]; 
//2:在前缀和数组的[l,r]区间上加c 等价于 在差分数组上b[l] += c;b[r+1] -= c;
        b[l] += c;
        b[r + 1] -= c;
//3:把差分数组转化为为操作完后的前缀和数组

        for(int i = 1 ; i <= n ; i++) b[i] = b[i-1] + b[i]; 

4)差分矩阵

import java.util.*;

public class Main{
    
    private static int N = 1010;
    
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int m = scan.nextInt();
        int q = scan.nextInt();
        
        int[][] arr = new int[N][N];
        int[][] dif = new int[N][N];
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                arr[i][j] = scan.nextInt();
                insert(i, j, i, j, dif, arr[i][j]);
            }
        }
        
        while(q -- > 0){
            int x1 = scan.nextInt();
            int y1 = scan.nextInt();
            int x2 = scan.nextInt();
            int y2 = scan.nextInt();
            int t = scan.nextInt();
            insert(x1, y1, x2, y2, dif, t);
        }
        
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                dif[i][j] = dif[i][j] + dif[i - 1][j] + dif[i][j - 1] - dif[i - 1][j - 1];
                System.out.print(dif[i][j] + " ");
            }
            System.out.println();
        }
        
        scan.close();
        
    }
    
    private static void insert(int x1, int y1, int x2, int y2, int[][] dif, int t){
        dif[x1][y1] += t;
        dif[x1][y2 + 1] -= t;
        dif[x2 + 1][y1] -= t;
        dif[x2 + 1][y2 + 1] += t;
    }
}

7.双指针算法

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;

    // 具体问题的逻辑
}
常见问题分类:
    (1) 对于一个序列,用两个指针维护一段区间
    (2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

 

 

import java.util.*;

public class Main{
    
    private static int N = 100010;
    private static int[] a = new int[N];
    private static int[] s = new int[N];
    
    public static void main(String[] args){
        int ans = 0;
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        for(int i = 0; i < n ;i ++){
            a[i] = scan.nextInt();
        }
        
        for(int i = 0,j = 0;i < n;i++){
            s[a[i]]++;
            while(s[a[i]] > 1){
                s[a[j]]--;
                j++;
            }
            ans = Math.max(ans, i - j + 1);
        }
        
        System.out.println(ans);
    }
}

8.位运算

1)获取数字 n的二进制的第 k位是多少

for (int i = n; i >= 0; i--) {
    System.out.print(x >> i & 1);
}
//先将二进制数向右移动 k位(此时 k位移动到了第一位), 操作: x >> i
//获取最后一位的值, 操作: 移动后的值 & 1
//两步和为一步操作: x >> i & 1

2)lowBit

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        while(n -- > 0){
            int tmp = scan.nextInt();
            int ans = 0;
            while(tmp != 0){
                tmp -= tmp & (-tmp);
                ans++;
            }
            System.out.print(ans + " ");
        }
    }
}


模版:int lowbit(int x){
    return x & -x;
    //-x = ~x + 1 //(x取反加1)
}

9.离散化

 

import java.util.*;

// 存储add中的x, c; query中的l, r
class Pair {
    int x, y;
    Pair(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

public class Main {
    public static void main(String[] args) {
        
        List<Pair> add = new ArrayList();   // 在x位置加c
        List<Pair> query = new ArrayList(); // 询问[l, r]区间和
        Set<Integer> set = new TreeSet();   // 涉及到的位置 x, l, r
        Map<Integer, Integer> map = new HashMap(); // 将位置映射到[1, n]
        
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int m = scan.nextInt();
        
        for (int i = 0; i < n; i++) {
            int x = scan.nextInt();
            int c = scan.nextInt();
            add.add(new Pair(x, c));    // 输入x, c
            set.add(x);                 // 坐标x加入有序set
        }
        for (int i = 0; i < m; i++) {
            int l = scan.nextInt();
            int r = scan.nextInt();
            query.add(new Pair(l, r));  // 输入l, r
            set.add(l);                 // 坐标l, r加入set
            set.add(r);
        }
        
        int index = 1;
        for (int x : set) {
            map.put(x, index++);    // 将坐标映射到[1, n]
        }
        
        int k = set.size();
        int[] nums = new int[k + 1];
        int[] sum = new int[k + 1];
        
        // 坐标x映射到index,给num[index]加上c
        for (int i = 0; i < n; i++) {
            Pair p = add.get(i);
            index = map.get(p.x);
            nums[index] += p.y;
        }
        
        // 求区间和
        for (int i = 1; i <= k; i++) {
            sum[i] = sum[i - 1] + nums[i];
        }
        
        // 将询问映射到[1, n]的坐标,求解区间和
        for (int i = 0; i < m; i++) {
            int l = query.get(i).x;
            int r = query.get(i).y;
            int ans = sum[map.get(r)] - sum[map.get(l) - 1];
            System.out.println(ans);
        }
    }
}

10.区间合并

​​​​​​​

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int[][] a = new int[n][2];
        for(int i = 0 ;i < n; i++){
            a[i][0] = scan.nextInt();
            a[i][1] = scan.nextInt();
        }
        
        Arrays.sort(a, new Comparator<int[]>(){
            public int compare(int[] o1, int[] o2){
                return o1[0] - o2[0];
            }
        });
        
        int res = 0;
        int r = Integer.MIN_VALUE;
        for(int i = 0; i < n; i++){
            if(r < a[i][0]){
                res ++;
            }
            r = Math.max(r, a[i][1]);
        }
        
        System.out.println(res);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值