基础算法第一章(java)

一、基础算法

1、快速排序

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class quickSort {
    public static void main(String[] args) throws IOException {
        BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(buf.readLine());
        String []nums = buf.readLine().split(" ");
        int []a = new int[n];
        for (int i = 0; i < nums.length; i++) {
            a[i] = Integer.valueOf(nums[i]);
        }
        quick_sort(a, 0, n - 1);
        for (int i = 0; i < n; i++) {
            System.out.print(a[i]+" ");
        }
        buf.close();
    }
    private static void  quick_sort(int[]a, int l, int r){
        if(l>=r){
            return;
        }
        int x = a[l];
        int i = l-1;
        int j = r+1;
        while(i<j){
            do{
                i++;
            }while(a[i]<x);
            do{
                j--;
            }while(a[j]>x);
            if(i<j){
                int t = a[i];
                a[i] = a[j];
                a[j] = t;
            }

        }
        quick_sort(a , l , j);
        quick_sort(a, j+1 , r);
    }
}

2、归并排序

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class margeSort {
    public static void main(String[] args) throws IOException {
        BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(buf.readLine());
        String[] a = buf.readLine().split(" ");
        int q[] = new int[n];
        for(int i = 0;i<n;i++){
            q[i] = Integer.valueOf(a[i]);
        }
        marge_sort(q , 0 , n-1);
        for (int i = 0; i < q.length; i++) {
            System.out.println(q[i]);
        }
    }
    public static void marge_sort(int []q ,int l ,int r){
        if(l>=r){
            return;
        }
        int mid = l+r>>1;

        marge_sort(q , l , mid);
        marge_sort(q , mid+1 , r);

        int k = 0;
        int i = l;
        int j = mid+1;
        int temp[] = new int[q.length];

        while(i<=mid && j<=r){
            if(q[i]>q[j]){
                temp[k++] = q[j++];
            }else{
                temp[k++] = q[i++];
            }
        }
        while(i<=mid){
            temp[k++] = q[i++];
        }
        while(j<=r){
            temp[k++] = q[j++];
        }

        for(int x = l,w = 0;x<=r;x++,w++){
           q[x] = temp[w];
        }
    }
}

归并排序模板思路:首先进行递归,将所有的元素分成一小块一小块然后逐层进行归并,归并时设置一个临时数组用来存放比较后的数据,由于每次递归使用的元素都不一样,所以在归并时元素会被分成两组两组,不断向上进行比较,到最后一次归并只剩下两个有序数组,这是对这两个有序数组进行比较

1、设置返回语句

2、取到中间值

3、递归左边,递归右边

4、设置临时数组,临时数组指针,目标数组的两个指针

5、比较两个数组元素大小,然后将数组剩下的元素拼接到临时数组中

6、将临时数组的元素返回到数组中

y总笔记:

1、确定临界点:mid = l+r>>1;

2、递归左右两边

3、归并——合二为一

ACWing.788:逆序对的数量:

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int a[] = new int[n];
        for(int i =0;i<n;i++){
            a[i] = sc.nextInt();
        }
        long sum = marge_sort(a , 0 , n-1);
        System.out.println(sum);
    }
    public static long marge_sort(int q[] ,int l ,int r){
        if(l>=r){
            return 0;
        }
        long res = 0L;
        int mid = l+r>>1;
        int temp[] = new int[r-l+1];
        res += marge_sort(q , l , mid)+marge_sort(q , mid+1 , r);
        int i = l;
        int j = mid+1;
        int k = 0;
        
        while(i<=mid&&j<=r){
            if(q[i]<=q[j]){
                temp[k++] = q[i++];
            }else {
                temp[k++] = q[j++];
                res += mid -i +1;
            }
        }
        
        while(i<=mid){
            temp[k++] = q[i++];
        }
        while(j<=r){
            temp[k++] = q[j++];
        }
        
        for(i = l,j=0;i<=r; i++,j++){
            q[i] = temp[j];
        }
        return res;
    }
}

3、二分

在这里插入图片描述

先写check函数,判断l=mid还是r=mid,如果是l = mid,那么mid = l+r+1>>1,如果是r = mid,那么mid = l+r>>1。

二分思路:

先写出check函数,判断check函数true返回的结果是左边界等于mid,还是右边界等于mid。

如果左边界等于mid,则mid需要向上取整,即mid=l+r+1/2

如果右边界等于mid,则mid需要向下取整,即mid=l+r

模板1:

int mid = l + r + 1>>1;
if(check(mid)){
    l = mid;
}else r = mid -1;

模板2:

int mid = l+r>>1;
if(check(mid)){
	r = mid;
}else l = mid +1;

要点是判断mid开始的取值,如果判断结果取了l = mid ,则mid = l +r+1>>1

如果判断取了r = mid , 则mid = l+r>>1;

ACWing.789:

import java.util.Scanner;

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

ACWing:T790

import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        double x = sc.nextDouble();
        double l = 0;
        double r = Math.abs(x)+1;
        
        while(r - l>1e-8){
            double mid = (l+r)/2;
            if(mid*mid*mid>=Math.abs(x)){
                r = mid;
            }else l = mid;
        }
        
        if(x>=0){
            System.out.printf("%.6f" , r);
        }else{
            System.out.print("-");
            System.out.printf("%.6f" , r);
        }
    }
    
}

4、高精度加法

用代码体现运算过程

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

public class Main{
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String a = bf.readLine();
        String b = bf.readLine();
        List<Integer> list = add(a , b);
        for(int i = list.size()-1;i>=0;i--){
            System.out.print(list.get(i));
        }
    }
    public static List<Integer> add(String a, String b){
        int i = a.length()-1;
        int j = b.length()-1;
        List<Integer> res = new ArrayList<>();
        int t = 0;
        for(;i>=0||j>=0 ;i--,j--){
            t+=(i>=0?a.charAt(i)-'0':0)+(j>=0?b.charAt(j)-'0':0);
            res.add(t%10);
            t = t/10;
        }
        if(t!=0)res.add(t);
        return res;
    }
}

4、高精度减法

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

public class GaoJingJian {
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String a = bf.readLine();
        String b = bf.readLine();

        ArrayList<Integer> aa = new ArrayList<>();
        ArrayList<Integer> bb = new ArrayList<>();
        for(int i = a.length()-1;i>=0;i--){
            aa.add(a.charAt(i)-'0');
        }
        for(int i = b.length()-1;i>=0;i--){
            bb.add(b.charAt(i)-'0');
        }

        if(check(a , b)){
            List<Integer> cc = sub(aa , bb);
            for(int i = cc.size()-1;i>=0;i--){
                System.out.print(cc.get(i));
            }
        }else {
            List<Integer> cc = sub(bb , aa);
            System.out.print('-');
            for(int i = cc.size()-1;i>=0;i--){
                System.out.print(cc.get(i));
            }
        }
    }
    public static boolean check(String a , String b){
        if(a.length()!=b.length()){
            return a.length()>b.length();
        }

        for(int i = 0;i<a.length();i++){
            if(a.charAt(i)!=b.charAt(i)){
                return a.charAt(i)>b.charAt(i);
            }
        }

        return true;
    }
    public static List<Integer> sub(ArrayList<Integer> a , ArrayList<Integer> b){
        List<Integer> list = new ArrayList<>();

        for(int i = 0 , t = 0;i<a.size();i++){
            t = a.get(i) - t;

            if(i<b.size()) t = t - b.get(i);
            list.add((t+10)%10);
            if(t<0) t = 1;else t = 0;
        }

        int i = list.size()-1;
        while(i>0){
            if(list.get(i)==0){
                i--;
            }else break;
        }
        return list.subList(0 , i+1);
    }
}

高精度减法思路:首先判断两个数大小,通过判断结果决定是否输出负号

然后利用一个变量t表示向前借位,(t+10)%10,如果t为整数,那么该数不变,最后将该数赋值为0,如果t为负数,那么该数成功向前一位借位,最后将该数赋值为1。

最后去除前导零。

5、高精度乘法

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

public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String a = br.readLine();
        int bb = Integer.valueOf(br.readLine());

        ArrayList<Integer> aa = new ArrayList<Integer>();

        for (int i = a.length() - 1; i >= 0; i--){
            aa.add(a.charAt(i) - '0');
        }



        ArrayList<Integer> c = add2(aa,bb);
        boolean t = true;
        for(int k = c.size() - 1; k >= 0 ; k--){
            if(c.get(k) == 0 && t && k >= 1) continue;
            System.out.print(c.get(k));
            t = false;
        }

    }

    public static ArrayList<Integer> add2(ArrayList<Integer> aa, int bb){
        ArrayList<Integer> c = new ArrayList<Integer>();
        int t = 0;
        for(int i = 0; i < aa.size(); i++){

            t += aa.get(i) * bb;

            c.add((t % 10));
            t /= 10;
        }
        if (t > 0) c.add(t);
        int i = 0;

        return c;
    }
}

评价:不如BigInteger

6、前缀和

前缀和总结:

思路:s[r]-s[l-1]

import java.util.Scanner;

public class Main{
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int a[] = new int[n+1];
        int s[] = new int[n+1];
        for(int i = 1;i<=n;i++){
            a[i] = sc.nextInt();
        }
        for(int i = 1;i<=n;i++){
            s[i] = a[i] + s[i-1];
        }
        while(m-->0){
            int l = sc.nextInt();
            int r = sc.nextInt();
            System.out.println(s[r] - s[l-1]);
        }
    }
}

s[i , j] - s[i-1 , j] - s[i , j-1] + s[i-1 , j-1]:
在这里插入图片描述
在这里插入图片描述

7、差分

差分最重要的就是,可以在差分数组中,批量的对原数组进行操作。

T797:

import java.util.*;

public class Main{
    
    static int N = 100010;
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int []arr = new int[N];
        int []b = new int[N];
        for(int i = 1;i<=n;i++){
            arr[i] = sc.nextInt();
        }
        
        for(int i = 1;i<=n;i++){
            insert(b , i , i , arr[i]);
        }
        
        for(int j = 0;j<m;j++){
            int l = sc.nextInt();
            int r = sc.nextInt();
            int c = sc.nextInt();
            
            insert(b , l , r , c);
            
        }
        
        for(int i = 1;i<=n;i++){
            b[i] = b[i] + b[i-1];
            System.out.print(b[i]+" ");
        }
        
        
    }
    
    public static void insert(int b[] , int l , int r , int c){
        b[l] = b[l]+c;
        b[r+1] = b[r+1]-c;
    }
}

T798:差分矩阵

import java.util.*;

public class Main{
    static int N = 1010;
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int q = sc.nextInt();
        
        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] = sc.nextInt();
            }
        }
        
        // 初始化差分b数组
        
        for(int i = 1;i<=n;i++){
            for(int j = 1;j<=m;j++){
                insert(b , i , j , i , j ,a[i][j]);
            }
        }
        
        while(q--!=0){
            int x1 = sc.nextInt();
            int y1 = sc.nextInt();
            int x2 = sc.nextInt();
            int y2 = sc.nextInt();
            int c = sc.nextInt();
            
            insert(b , x1 , y1 , x2 , y2 , c);
            
            
        }
        
        for(int i = 1;i<=n;i++){
            for(int j = 1;j<=m;j++){
                a[i][j] = b[i][j] - a[i-1][j-1] + a[i][j-1] + a[i-1][j];
                System.out.print(a[i][j]+" ");
            }
            System.out.println();
        }
        
        
        
    }
    public static void insert(int b[][] , int x1 , int y1 , int x2 , int y2 , int c){
        b[x1][y1] += c;
        b[x2+1][y2+1] += c;
        b[x2+1][y1] -= c;
        b[x1][y2+1] -= c;
    }
}

8、双指针

模板:

for(int i = 0 , j = 0;i<n;i++){
    while(j<i&&check(j))j++;
    //具体题的逻辑
}

T799:

import java.util.*;

public class Main{
    static int N = 100010;
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[N];
        int[] s = new int[N];
        for(int i = 0;i<n;i++){
            a[i] = sc.nextInt();
        }
        
        int j = 0;
        int res = 0;//结果
        //for内部:
        //每次i往前走一个,判断该数是否重复,如果不重复,i继续往前走
        //如果重复,j往前走,同时将已经放入判重数组的元素踢掉,直到走到重复元素为止
        //此时j<i,因为j走到的是与i为下标的相等的元素上
        for(int i = 0;i<n;i++){
            s[a[i]] ++ ;
            while(s[a[i]]>1){
                s[a[j]]--;
                j ++;
            }
            
            res = Math.max(res , i - j +1);
        }
        
        System.out.println(res);
    }
}

9、位运算

常见的位运算操作:

n的二进制表示中第k位是几

求n的第k位数字:n>>k&1

返回n的最后一位1:lowbit(n) = n& -n

lowbit(x):返回最后一位1

10、离散化

1、数组中可能有重复元素(去重)

2、需要快速的映射,如何算出a[i]离散化后的值(二分)

//储存所有离散化的值
//排序所有值
//去重
import java.util.*;

public class Main{
    static int N = 300010;
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();//存n次操作
        int m = sc.nextInt();//存m次询问
        int[] a = new int[N];
        int[] s = new int[N];

        List<Integer> list = new ArrayList<>();//存数轴
        List<Paris> add = new ArrayList<>();//存n次操作
        List<Paris> query = new ArrayList<>();//存m次询问

        for(int i = 0;i<n;i++){
            int first = sc.nextInt();
            int second = sc.nextInt();
            add.add(new Paris(first , second));
            list.add(first);
        }

        for(int i = 0;i<m;i++){
            int first = sc.nextInt();
            int second = sc.nextInt();
            query.add(new Paris(first , second));
            list.add(first);
            list.add(second);
        }

        Collections.sort(list);
        int un = unic(list);
        list = list.subList(0 , un);

        for(Paris item : add){
            int x = find(item.first , list);
            a[x] += item.second;
        }

        for(int i = 1;i<=list.size();i++) s[i] = s[i-1]+a[i];


        for(Paris item : query){
            int l = find(item.first , list);
            int r = find(item.second , list);
            System.out.println(s[r] - s[l-1]);
        }
    }

    static int find(int x, List<Integer> list){
        int l = 0;
        int 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;
    }//二分查询,前缀和是以1开始,所以结尾要加1

    static int unic(List<Integer> list){
        int j = 0;
        for(int i = 0;i<list.size();i++){
            if(i == 0||list.get(i)!=list.get(i-1)){
                list.set( j , list.get(i));
                j++;
            }
        }
        return j;
    }//去重操作

}

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

思路:

使用一个容器来储存所有的值,使用一个集合作为映射集合(下标对应数组下标,集合内对应元素),使用一个数组作为被操作数组。

11、区间合并

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        List<int[]> list = new ArrayList<>();
        List<int[]> res = new ArrayList<>();

        for(int i = 0;i<n;i++){
            int first = sc.nextInt();
            int second = sc.nextInt();
            list.add(new int[]{first , second});
        }

        list.sort(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] - o2[0];
            }
        });

        int st = Integer.MIN_VALUE;
        int ed = Integer.MIN_VALUE;
        for(int[] a : list){
            if(a[0]>ed){
                if(st !=Integer.MIN_VALUE){
                    res.add(new int[]{st , ed});
                }
                st = a[0];
                ed = a[1];
            }else{
                ed = Math.max(ed , a[1]);
            }
        }
        if (st != Integer.MIN_VALUE){
            res.add(new int[]{st , ed});
        }
        System.out.println(res.size());
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值