acwing基礎算法



title: acwing基礎算法
date: 2021-01-23 09:22:59
tags:
-算法
-acwing
categories: 算法


從今天開始acwing的學習,預計基礎班一周看完和寫完,懷挺!!!

acwing基礎班一

快速排序

步驟

image-20210123092937637

注意快排的核心思想是分治法:

分解:兩個片段,一個大於x,一個小於x,並且遞歸的調用,partition

解決:和分治合在一起即partition

合並:無特別步驟,自動合並(在左右端點到達最小以后)

關鍵步驟在於2

解決方法

1、暴力開空間

開辟兩個空間,分別放置大於小於x的數,再合並

時間O(n),空間O(n)

2、partition法

Scanner類的用法參考https://www.runoob.com/java/java-scanner-class.html

package acwing基礎算法;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Scanner;

public class quicksort {

    public static void quick_sort(int []arr,int l,int r){
        if(l>=r) return;

        int i=l-1,j=r+1,x=arr[l];
        while(i<j){
            do i++;while(arr[i]<x);
            do j--;while (arr[j]>x);
            if(i<j){
                int t=arr[i];
                arr[i]=arr[j];
                arr[j]=t;
            }
        }
        quick_sort(arr,l,j);
        quick_sort(arr,j+1,r);
    }

    public static void main(String[] args) {

        Scanner scannerIn = new Scanner(new BufferedInputStream(System.in));
        //獲取數組長度,並分配數組空間
        int n = scannerIn.nextInt();
        int q[]=new int[n];
        //為數組賦值
        for(int i=0;i<n;i++){
            q[i]=scannerIn.nextInt();
        }
        quick_sort(q ,0,n-1);
        //打印數組
        System.out.println(Arrays.toString(q));
    }

}

3、快速選擇算法

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Scanner;
//改寫快速排序算法

public class Main {

    public static int quick_sort(int []arr,int l,int r,int k){
        if(l==r) return arr[l];

        int i=l-1,j=r+1,x=arr[l];
        while(i<j){
            do i++;while(arr[i]<x);
            do j--;while(arr[j]>x);
            if(i<j){
                int t=arr[i];
                arr[i]=arr[j];
                arr[j]=t;
            }
        }
        if(k<=j-l+1)
            return quick_sort(arr,l,j,k);
        else
            return quick_sort(arr,j+1,r,k-(j-l+1));
    }

    public static void main(String[] args) {

        Scanner scannerIn = new Scanner(new BufferedInputStream(System.in));
        //獲取數組長度,並分配數組空間
        int n = scannerIn.nextInt();
        int k = scannerIn.nextInt();
        int q[]=new int[n];
        //為數組賦值
        for(int i=0;i<n;i++){
            q[i]=scannerIn.nextInt();
        }
        //打印結果
        System.out.print(quick_sort(q ,0,n-1,k-1));
        
    }

}

注意事項

1、邊界問題:理論上可以選取樞紐元素問題時可以選擇l,r和(l+r)/2,隨機選擇

但是注意邊界條件,當選擇i和i-1作為遞歸界時,不能使用l作為樞紐元素;

同理不能使用j,j+1作為遞歸界,當使用r作為樞紐元素時

用r+l>>1時如果是用i做邊界要變成r+l+1>>1

2、停止一次partition的可能情況i=j或者i+1=j

3、快速排序的partition有多種寫法,常見的還有算法導論上的寫法,同向移動雙指針(了解即可)

4、快排是不穩定排序,可以把快排的數變成二維(有下標)這樣每個數都不相同了,變成穩定的

歸並排序

基本思想

image-20210123111849527

算法

package acwing基礎算法;

import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;

public class MergeSort {
    public static void merge_sort(int l,int r,int []arr){

        if(l>=r) return;
        //防止溢出
        int mid=l+((r-l)>>1);
        merge_sort(l,mid,arr);
        merge_sort(mid+1,r,arr);
        //我們不希望arr的引用發生改變,因為arr的引用發生改變,那么需要再次返回一個arr的引用給q,但是這里arr是局部變量
        //因此我們希望arr指向的內容發生改變
        merge(l,mid,r,arr);
    };

    private static int[]q;
    private static int[]temp;

    public static void merge(int l,int mid,int r,int []arr){

        temp=new int[r-l+1];
        int i=l,j=mid+1,index=0;
        while(i<=mid&&j<=r){
            if(arr[i]<=arr[j])
                temp[index++]=arr[i++];
            else
                temp[index++]=arr[j++];
        }
        while(i<=mid) temp[index++]=arr[i++];
        while(j<=r) temp[index++]=arr[j++];
        for(i=l,j=0;i<=r;i++,j++) arr[i]=temp[j];
//        return temp;
    };

    public static void main(String[] args) {
        Scanner scannerIn = new Scanner(new BufferedInputStream(System.in));
        int n = scannerIn.nextInt();
        q = new int[n];
        for(int i=0;i<n;i++){
            q[i] = scannerIn.nextInt();
        }
        merge_sort(0,n-1,q);
        System.out.println(Arrays.toString(q));
        scannerIn.close();
    }


}

注意事項

1、出錯點1是因為我在合並時的條件寫的是<實際應該是<=,即等於也需要被算進輔助數組

2、一定要注意數組傳遞是引用傳遞,即變量名指向的地址發生變化。因此形參傳遞數組,就是局部變量指向了被傳遞的數組,同理局部返回數組名,就是返回了局部的數組地址。(局部數組后被釋放,需要改成全局數組)

3、最簡單的做法就是在merge函數中直接改變arr數組的值,因為arr數組指向的就是q數組

4、 int mid=l+((r-l)>>1);是為了防止溢出

5、 temp=new int[r-l+1];不要錯寫成分配成new int[arr.length];

二分

整數二分

有單調性的一定可以二分,但能二分的不一定有單調性

image-20210123214222926

深刻認識,就是滿足某一條件的最大值或者滿足某一條件的最小值,縮小區間來尋找這個介於滿足與不滿足之間的臨界值

l=mid時,我們選擇mid=(l+r+1)/2,為了避免死循環

如果無解一定與題目有關

模板


import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {

    public static void twoDivide(int[]arr,int target){
        int l=0,r=arr.length-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+" ");
                l=0;r=arr.length-1;
                while (l < r) {
                    int mid = l + r + 1 >> 1;
                    if (arr[mid] <= target) l = mid;
                    else r = mid - 1;
                }
                System.out.println(l);
            }
        }


    public static void main(String[] args) {
        Scanner in = new Scanner(new BufferedInputStream(System.in));
        int n = in.nextInt();
        int []q=new int[n];
        int k=in.nextInt();
        for(int i=0;i<n;i++){
            q[i]=in.nextInt();
        }
        while(k--!=0){
            twoDivide(q,in.nextInt());
        }
    }
}

浮點數二分

寫法一

和整數二分模板一樣,但是mid不再加1減1,且判斷條件有個臨界值,一般比精度大10的-2次方

package acwing基礎算法;

import java.io.BufferedInputStream;
import java.util.Scanner;

public class DoubleTwoDivide {


    public static void main(String[] args) {
        Scanner in = new Scanner(new BufferedInputStream(System.in));
        double x = in.nextDouble(),l=0,r=Math.abs(x);
        while(r-l>1e-8){
            double mid=(l+r)/2;
            if(mid*mid*mid>=Math.abs(x))r=mid;
            else l=mid;
        }
        boolean flag;
        if (x>=0)
            flag=true;
        else
            flag=false;
        System.out.println(String.format("%.6f",flag?l:-l));
    }
}

寫法二

直接for循環一百次或者縮小范圍,那精度絕對是夠的

public class Main{

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        double num = sc.nextDouble();
        boolean flag = false;
        if(num < 0) {
            flag = true;
            num = -num;
        }

        double l = 0d, r = 100d;
        while (r - l > 1e-8) {
            double mid = (l + r) / 2;
            if(mid * mid * mid < num) {
                l = mid;
            } else {
                r = mid;
            }
        }

        System.out.println(String.format("%.6f", flag? -l:l));
    }
}

高精度加法

BufferedReader類的用法

以下內容參考至https://blog.csdn.net/StrongHelper/article/details/84697087

System.in的類型可以歸結為節點流、字節流、輸入流;
InputStreamReader這個對象是處理流,字符流,輸入流;
BufferedReader的類型是緩沖處理流、字符流、輸入流。

類 InputStreamReader是字節流通向字符流的橋梁:它使用指定的 charset 讀取字節並將其解碼為字符。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平台默認的字符集。如:GBK
每次調用 InputStreamReader 中的一個 read() 方法都會導致從底層輸入流讀取一個或多個字節。要啟用從字節到字符的有效轉換,可以提前從底層流讀取更多的字節,使其超過滿足當前讀取操作所需的字節。 為了達到最高效率,可要考慮在 BufferedReader 內包裝 InputStreamReader。例如: BufferedReader in= new BufferedReader(new InputStreamReader(System.in));

System.in是個字節流

InputStreamReader是個字符流和字節流之間的轉換中介

BufferedReader是個字符流
整體意思就是用InputStreamReader這個中介把System.in這個字節流轉換成字符流BufferedReader
這樣輸入的時候就可以不是一個一個字節讀,而是一個一個字符讀,再加上是個Buffer,效率會高很多。
InputStream is = System.in;//鍵盤輸入流
InputStreamReader isr = new InputStreamReader(is);//字節流轉換為字符流
BufferedReader bufr = new BufferedReader(isr);//把字符流添加到緩沖流

BigInteger用法

以下內容參考自https://blog.csdn.net/qq_41668547/article/details/87628618

java中可以使用BigInteger操作大整數,也可以轉換進制。如果在操作的時候一個整型數據已經超過了整數的最大類型長度long的話,則此數據就無法裝入,所以,此時要使用BigInteger類進行操作。這些大數都會以字符串的形式傳入

split的用法

參考自https://www.cnblogs.com/xiaoxiaohui2015/p/5838674.html

算法模板

package acwing基礎算法;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;


public class HighPrecision {
    public static void main(String[] args) throws IOException {
//            highAdd();
//            highSub();
//            highMultiply();
            highDivide();
        }

    public static void highAdd() throws IOException {
        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
        String[] s = cin.readLine().split(" ");
        BigInteger n = new BigInteger(s[0]);
//            System.out.println(1);
        s = cin.readLine().split(" ");
        BigInteger m = new BigInteger(s[0]);
        System.out.println(m.add(n));
    }

    public static void highSub() throws IOException {
        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
        String[] s = cin.readLine().split(" ");
        BigInteger n = new BigInteger(s[0]);
//            System.out.println(1);
        s = cin.readLine().split(" ");
        BigInteger m = new BigInteger(s[0]);
        System.out.println(n.subtract(m));
    }

    public static void highMultiply() throws IOException {
        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
        String[] s = cin.readLine().split(" ");
        BigInteger n = new BigInteger(s[0]);
//            System.out.println(1);
        s = cin.readLine().split(" ");
        BigInteger m = new BigInteger(s[0]);
        System.out.println(n.multiply(m));
    }

    public static void highDivide() throws IOException {
        BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
        String[] s = cin.readLine().split(" ");
        BigInteger n = new BigInteger(s[0]);
//            System.out.println(1);
        s = cin.readLine().split(" ");
        BigInteger m = new BigInteger(s[0]);
        System.out.println(n.divide(m));
//        System.out.println(n.divide(m).multiply(m));
//        System.out.println(n.subtract(n.divide(m).multiply(m)));
        System.out.println(n.remainder(m));
    }
}

前綴和

算法思想

image-20210124075850599

我們把S0定義成0

算法模板

package acwing基礎算法;

import com.sun.org.apache.bcel.internal.Const;

import java.io.BufferedInputStream;
import java.util.Scanner;

public class PreSum {

    private static final int N=100010;

    public static void main(String[] args) {
        Scanner in = new Scanner(new BufferedInputStream(System.in));
        int n = in.nextInt();
        //m次輸入
        int m = in.nextInt();
        int[] q = new int[N];
        int[] s = new int[N];
        //輸入數組
        for (int i = 1; i <= n; i++) {
            q[i]=in.nextInt();
        }

        for(int i=1;i<=n;i++){
            s[i]=s[i-1]+q[i];
        }
        //m次結果輸出
        while(m--!=0){
            //輸入數的范圍l,r
            int l=in.nextInt(),r=in.nextInt();
            System.out.println(s[r]-s[l-1]);
        }
    }
}

多維

image-20210124091642348

上面修正為加最后一個式子修正為加Sx1-1,y-1

package acwing基礎算法;

import java.io.BufferedInputStream;
import java.util.Scanner;

public class PreMultiSum {
    private static final int N = 1010;
    public static void main(String[] args) {
        Scanner in = new Scanner(new BufferedInputStream(System.in));
        //n行
        int n = in.nextInt();
        //m列
        int m = in.nextInt();
        int q = in.nextInt();
        int [][]a = new int[N][N];
        int [][]s = new int[N][N];
        //二維數組賦值
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                a[i][j] = in.nextInt();
            }
        //求完整和
        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][j];
            }
        //求部分和
        while(q--!=0){
            int x1=in.nextInt(),y1=in.nextInt(),x2=in.nextInt(),y2=in.nextInt();
            System.out.println(s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);
        }
    }
}

差分

前綴和的逆運算

image-20210124172645285

模板

package acwing基礎算法;

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Difference {

    private static final int N=100010;
    public static void insert(int l,int r,int x,int []b){
        b[l]+=x;
        b[r+1]-=x;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(new BufferedInputStream(System.in));
        int n = in.nextInt(),m = in.nextInt();
        int[] a = new int[N];
        int[] b = new int[N];
        //給a數組賦值
        for(int i=1;i<=n;i++){
            a[i]=in.nextInt();
        }
        //按a數組構造b數組
        for(int i=1;i<=n;i++){
            insert(i,i,a[i],b);
        }
        //多次輸入,給出每次修改的差分數列后的結果
        while(m--!=0){
            int l=in.nextInt(),r=in.nextInt(),c=in.nextInt();
            insert(l,r,c,b);

        }
        //重新求和數列同時注意b[0]等於0
        for(int i=1;i<=n;i++){
            b[i]+=b[i-1];
        }
        for(int i=1;i<=n;i++){
            System.out.print(b[i]+" ");
        }

    }
}

差分矩陣

算法思想

image-20210124180728294

超時

scanner超時
import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {

    private static final int N=1010;

    public static void insert(int x1,int y1,int x2,int y2,int c,int [][]b){
           b[x1][y1]+=c;
           b[x2+1][y1]-=c;
           b[x1][y2+1]-=c;
           b[x2+1][y2+1]+=c;
    }
    public static void main(String[] args) {

        Scanner in = new Scanner(new BufferedInputStream(System.in));
        int n = in.nextInt(),m = in.nextInt();//n行m列
        int q = in.nextInt();//q次運算

        int [][]a = new int[N][N];
        int [][]b = new int[N][N];

        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                a[i][j]=in.nextInt();


        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                insert(i,j,i,j,a[i][j],b);

        while(q--!=0){

            int x1 = in.nextInt(),y1 = in.nextInt(),x2 = in.nextInt(),y2 = in.nextInt(),c = in.nextInt();
            insert(x1,y1,x2,y2,c,b);


        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) {
                b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];

            }
        for(int i=1;i<=n;i++) {
            for (int j = 1; j <= m; j++) {
                System.out.print(b[i][j] + " ");
            }
            System.out.println();
        }
    }
}

輸入流還是超時
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Main {

    private static final int N=1010;

    public static void insert(int x1,int y1,int x2,int y2,int c,int [][]b){
           b[x1][y1]+=c;
           b[x2+1][y1]-=c;
           b[x1][y2+1]-=c;
           b[x2+1][y2+1]+=c;
    }
    public static void main(String[] args) throws IOException {


        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String[] s1 = reader.readLine().split(" ");
        int n = Integer.parseInt(s1[0]),m = Integer.parseInt(s1[1]);
        int q = Integer.parseInt(s1[2]);
        int [][]a = new int[N][N];
        int [][]b = new int[N][N];


        for(int i=1;i<=n;i++) {
            String[] s2 = reader.readLine().split(" ");
            for (int j = 1; j <= m; j++) {
                a[i][j] = Integer.parseInt(s2[j - 1]);
                insert(i, j, i, j, a[i][j], b);
            }
        }

        while(q--!=0){
            String[] s3 = reader.readLine().split(" ");
            int x1 = Integer.parseInt(s3[0]),
            y1 = Integer.parseInt(s3[1]),
            x2 = Integer.parseInt(s3[2]),
            y2 = Integer.parseInt(s3[3]),
            c = Integer.parseInt(s3[4]);
            insert(x1,y1,x2,y2,c,b);
        }

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

            }
        for(int i=1;i<=n;i++) {
            for (int j = 1; j <= m; j++) {
                System.out.print(b[i][j] + " ");
            }
            System.out.println();
        }
    }
}

BufferedReader BufferedWriter加輸入輸出流

輸入流再加輸出流不超時

package acwing基礎算法;

import java.io.*;
import java.util.Scanner;

public class DifferenceMulti {

    private static final int N=1010;

    public static void insert(int x1,int y1,int x2,int y2,int c,int [][]b){
           b[x1][y1]+=c;
           b[x2+1][y1]-=c;
           b[x1][y2+1]-=c;
           b[x2+1][y2+1]+=c;
    }
    public static void main(String[] args) throws IOException {


        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        //BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] s1 = reader.readLine().split(" ");
        int n = Integer.parseInt(s1[0]),m = Integer.parseInt(s1[1]);
        int q = Integer.parseInt(s1[2]);
        int [][]a = new int[N][N];
        int [][]b = new int[N][N];


        for(int i=1;i<=n;i++) {
            String[] s2 = reader.readLine().split(" ");
            for (int j = 1; j <= m; j++) {
                a[i][j] = Integer.parseInt(s2[j - 1]);
                insert(i, j, i, j, a[i][j], b);
            }
        }

        while(q--!=0){
            String[] s3 = reader.readLine().split(" ");
            int x1 = Integer.parseInt(s3[0]),
            y1 = Integer.parseInt(s3[1]),
            x2 = Integer.parseInt(s3[2]),
            y2 = Integer.parseInt(s3[3]),
            c = Integer.parseInt(s3[4]);
            insert(x1,y1,x2,y2,c,b);
        }

        for(int i=1;i<=n;i++) {
            for (int j = 1; j <= m; j++) {
                b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
                //輸出
                writer.write(b[i][j] + " ");

            }
            writer.write("\n");
        }
        writer.flush();
        reader.close();
        writer.close();
    }
}

雙指針算法

算法思想

image-20210124203715705

最大不連續子數組

image-20210124210709837

image-20210124212313790

模板

import java.io.*;

public class Main {

    private static final int N = 100010;

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] s = in.readLine().split(" ");
        int n = Integer.parseInt(s[0]);
        int[] a = new int[N];
        //q是hash數組
        int[] q = new int[N];
        String[] s1 = in.readLine().split(" ");
        for(int i=1;i<=n;i++){
            a[i]=Integer.parseInt(s1[i-1]);
        }
        //雙指針算法
        //定義雙指針
        //res表示最大的長度
        int res=0;
        for(int i=1,j=1;i<=n;i++){
            q[a[i]]++;
            while(j<=i&&q[a[i]]>1)q[a[j++]]--;
            res=Math.max(res,i-j+1);
        }
        out.write(res+" ");
        out.flush();
        in.close();
        out.close();
    }


位運算

右移

image-20210124213138917

lowbit

image-20210124213306192

image-20210124213510311

應用

求解x的補碼中1的個數

模板

import java.io.*;

public class Main{

    private static final int N = 100010;

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] s = in.readLine().split(" ");
        int n = Integer.parseInt(s[0]);

        int[] a = new int[N];
        String[] s1 = in.readLine().split(" ");
        for(int i=1;i<=n;i++){
            a[i]=Integer.parseInt(s1[i-1]);
        }

        int i = 1;
        while(n--!=0){
            int k = 0;
            while(a[i]!=0){
                a[i]-=a[i]&(-a[i]);
                k++;
            }
            i++;
            out.write(k+" ");
        }
        out.flush();
        in.close();
        out.close();
    }
}

補充

1、原碼、反碼、補碼

image-20210124214204354

2、解題思路

image-20210124214457461

離散化

算法思想

image-20210124215221570

模板

image-20210124215153421

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    private static final int N = 300010;

    public static void main(String[] args) throws IOException {
        //輸入m,n
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] str = in.readLine().split(" ");
        //m行每行查詢,n行每行指定下標加
        int n = Integer.parseInt(str[0]),m = Integer.parseInt(str[1]);
        //a數組用來裝所有x和c和計算結果,sum數組用來裝前綴和
        int[] a = new int[N],sum = new int[N];
        //all數組用來裝所有的下標,收集所有下標,進行離散化
        List<Integer> all = new ArrayList<>();
        List<Pairs> add = new ArrayList<>();
        //query用來裝輸入的所有的查詢下標
        List<Pairs> query = new ArrayList<>();
        //輸入並放入add數組和all數組
        for(int i=1;i<=n;i++){
            String[] s2 = in.readLine().split(" ");
            int x = Integer.parseInt(s2[0]),c = Integer.parseInt(s2[1]);
            add.add(new Pairs(x,c));
            all.add(x);
        }
        //輸入並放入query數組和all數組
        for(int i=1;i<=m;i++){
            String[] s3 = in.readLine().split(" ");
            int l = Integer.parseInt(s3[0]),r = Integer.parseInt(s3[1]);
            query.add(new Pairs(l,r));
            all.add(l);all.add(r);
        }
        //開始離散化
        //1.排序
        Collections.sort(all);
        //2.去重
        int j=0;
        for(int i=0;i<all.size();i++){
            if(i==0||all.get(i)!=all.get(i-1)){
                all.set(j,all.get(i));
                j++;
            }
        }
        all = all.subList(0, j); //將去重后的List保存下來,或者此處也可以將unique作為最后一個數,用r作為二分
        //指定位置加
        for(Pairs items:add){
            int index=find(items.first,all);
            a[index]+=items.second;
        }
        //求前綴和
        for(int i=1;i<=all.size();i++) sum[i] = sum[i-1] + a[i];
        //查詢
        for(Pairs items:query) {
            int l = find(items.first, all);
            int r = find(items.second, all);
            System.out.println(sum[r] - sum[l - 1]);
        }
    }

    //查找函數(離散化映射函數,在離散化數組中找到映射的下標)
    public static int find(int x,List<Integer> list){
        int l=0,r=list.size()-1;
        while(l<r) {
            int mid = l+r>>1;
            if (list.get(mid) >= x) r = mid;
            else l = mid + 1;
        }
        return l+1;
    }
};
class Pairs{
    public int first;   
    public int second;
    
    public Pairs(int first,int second){
        this.first = first;
        this.second = second;
    }
}

注意

1、all數組由list裝載,因此下標從0開始,去重和進行查找函數時都從0開始。映射到1,n,所以查找離散函數時返回l+1

2、去重后改變all數組的長度all = all.subList(0, j);可以縮小定點相加和求前綴和的時間復雜度

補充

1、返回數組中所有不同的數

雙指針

image-20210124230343629

2、java去重

區間合並

區間有交集或者端點重合的區間可以合並為同一個區間

image-20210124231407864

package acwing基礎算法;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SectionMerge {
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s1 = in.readLine().split(" ");
        //n行輸入
        int n = Integer.parseInt(s1[0]);
        //輸入數組
//        int[] a = new int[N];
        List<Pairs> list = new ArrayList<>();
        List<Pairs> res = new ArrayList<>();
        for(int i=0;i<n;i++){
            String[] s2 = in.readLine().split(" ");
            int l = Integer.parseInt(s2[0]),r = Integer.parseInt(s2[1]);
            list.add(new Pairs(l,r));
        }
        //排序
        list.sort(new Comparator<Pairs>() {
            @Override
            public int compare(Pairs o1, Pairs o2) {
                return o1.first-o2.first;
            }
        });
        //現在維護的線段
        int st = Integer.MIN_VALUE,ed=Integer.MIN_VALUE;
        for(Pairs items:list){
//            System.out.println(ed);
            if(ed<items.first){
                if(st!=Integer.MIN_VALUE) res.add(new Pairs(st,ed));
                st = items.first; ed = items.second;
            }
            else{
                ed = Math.max(ed,items.second);
            }
        }
        if(st != Integer.MIN_VALUE) res.add(new Pairs(st,ed));
        System.out.println(res.size());
    }

}

class Pairs{

    int first;
    int second;

    public Pairs(int first, int second) {
        this.first = first;
        this.second = second;
    }
}

注意

最后還要再進行一次res.add,並且去除輸入數組為空的情況

習題:格子染色


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM