算法宝典高级

打印图形

面试题 01.07. 旋转矩阵(降低空间复杂度)

class Solution {
    public void rotate(int[][] matrix) {
        int a=0;
        int b=0;
        int c=matrix.length-1;
        int d=matrix[0].length-1;
        while(a<c){
            process(matrix,a++,b++,c--,d--);
        }
    }

    public void process(int[][] arr,int a,int b,int c,int d){
        int len = d-b;
        int temp=0;
        for(int i=0;i<len;i++){
            temp=arr[a][b+i];
            arr[a][b+i] = arr[c-i][b] ; 
            arr[c-i][b] = arr[c][d-i];
            arr[c][d-i] = arr[a+i][d];
            arr[a+i][d] = temp;
        }
    }
}

54. 螺旋矩阵(宏观上看 对角线夹逼法)

package class03;

import java.util.ArrayList;
import java.util.List;

class Solution {
    public static List<Integer> list = new ArrayList<>();
    public static List<Integer> spiralOrder(int[][] matrix) {
        //维护左上角和右下角的四个位置指针
        int a=0,b=0;
        int c=matrix.length-1,d=matrix[0].length-1;
        //打印一圈后向内缩
        while(a<=c&&b<=d){
            print(matrix,a++,b++,c--,d--);
        }
        return list;
    }

    //打印一圈
    public static void print(int[][] matrix, int a, int b, int c, int d){
        if(a==c){
            for(int i=b;i<=d;i++){
                list.add(matrix[a][i]);
            }
        }else if(b==d){
            for(int i=a;i<=c;i++){
                list.add(matrix[i][b]);
            }
        }else{
            int curB = b;
            int curA = a;
            while (curB != d) {
               list.add(matrix[a][curB]);
                curB++;
            }
            while (curA != c) {
                list.add(matrix[curA][d]);
                curA++;
            }
            while (curB != b) {
                list.add(matrix[c][curB]);
                curB--;
            }
            while (curA != a) {
                list.add(matrix[curA][b]);
                curA--;
            }
        }
    }

    public static void main(String[] args)  {
        int[][] arr = new int[][]{{1,2,3,4}
                                 ,{5,6,7,8}
                                 ,{9,10,11,12}};
            System.out.print(spiralOrder(arr));
        }
    }

蛇形矩阵

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int l=1;
        int[][] arr = new int[100][100];
        for(int i=1;i<=n;i++){
            for(int j=0;j<i;j++){
                arr[i-1-j][j]=l;
                l++;
            }
        }
        int h=0;
        for(int i=0;i<n;i++,h++){
            for(int j=0;j<n-h;j++){
                System.out.print(arr[i][j]+" ");
                if(i+j==n-1){
                    System.out.println();
                }
            }
        }
    }
}

枚举

分糖果

public class Main {
    static int res=0;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] m = new int[n];
        for(int i=0;i<n;i++){
            m[i] = scanner.nextInt();
        }
        //维护一个数组用来存放分了的数
        int[] num = new int[n];
        process(m);
        //判断数组是否糖果数相同,如有,返回奇数个数并奇数变偶数
        while(isj(m)){
            process(m);
        }
        System.out.println(res);
    }

    public static boolean isj(int[] m){
        int num =0;
        for(int i=0;i<m.length;i++){
            if(m[i]%2!=0){
                res++;
                m[i]+=1;
            }
        }
        for(int i=0;i<m.length-1;i++){
            if(m[i]!=m[i+1]){
                num++;
            }
        }
        if(num!=0){
            return true;
        }else{
            return false;
        }

    }

    public static int[] process(int[] m){
        int[] num = new int[m.length];
        for(int i=0;i<m.length;i++){
            m[i]=m[i]/2;
            num[i]=m[i];
        }
        for(int i=1;i<m.length;i++){
            m[i]=m[i]+num[i-1];
        }
        m[0] = m[0]+num[num.length-1];
        return m;
    }
}

矩阵相乘

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        int[][] arr = new int[n][n];
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                arr[i][j]= scanner.nextInt();
            }
        }

        if(m==0){
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(i==j){
                        System.out.print(1+" ");
                    }else{
                        System.out.print(0+" ");
                    }
                }
                System.out.println();
            }
            return;
        }

        int[][] res = arr;
        for(int i=1;i<m;i++){
            res = process(arr,res);
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                System.out.print(res[i][j]+" ");
            }
            System.out.println();
        }
    }

    //将arr 与 temp 相乘 结果保存为 arr
    public static int[][] process(int[][] arr,int[][] temp){
        int[][] res = new int[arr.length][arr.length];
        for(int i=0;i< arr.length;i++){
            for(int j=0;j< arr.length;j++){
                for(int p=0;p< arr.length;p++){
                    res[i][j]+= arr[i][p]*temp[p][j];
                }
            }
        }
        return res;
    }
}

说谎话

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[6];
        for(int i=0;i<arr.length;i++){
            arr[i] = 1;
            int res = 0;
            boolean A = false,B = false,C = false,D = false,E = false,F = false;
            if(arr[0]!=1){
                A = true;
                res++;
            }
            if(arr[0]==1||arr[2]==1){
                B = true;
                res++;
            }
            if(!A&&!B){
                C = true;
                res++;
            }
            if(arr[5]==1){
                F = true;
                res++;
            }
            if(!C&&!F){
                D = true;
                res++;
            }
            if(A&&!B&&!C&&D&&!F){
                E = true;
                res++;
            }
            if(res==3){
                System.out.println((char)(i+'A'));
            }
            arr[i] = 0;
        }
    }
}

2672 蓝桥杯2022年第十三届省赛真题-字符统计

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String str=sc.next();
    
        char[] arr = str.toCharArray();
        
        //sort(arr);
        int[] list = new int[26];
        for(int i=0;i<arr.length;i++){
            int j =  arr[i]-'A';
            list[j]++;
        }
        int min = -1 , r =-1;
        for(int i =0 ; i< list.length; i++){
            if(list[i]>min){
                r = i;
                min = list[i];
            }
        }
        int[] res = new int[list.length];
        for(int i =0 ; i< list.length; i++){
            if(list[i]==list[r]){
                res[i] = i+1;
            }
        }
        for(int i : res){
            if(i!=0){
                System.out.print((char)('A'+i-1));
            }
        }
    }
}

子矩阵问题

这类问题往往复杂度比较高,可以注意一下数据范围,将某一维度(数据量小)的数据压缩,使整体枚举数据量小的维度,另一数据量大的维度可以采用二分等策略简化复杂度,,大部分情况下都会使用dp来存储处理后的数据,以简化复杂度

最大子矩阵(求差)

2061: [蓝桥杯2022初赛] 最大子矩阵
题解

前缀和问题

前缀和可以简单理解为「数列的前 n项的和」,是一种重要的预处理方式,能大大降低查询的时间复杂度

前缀和有时会和哈希表一起使用,用来解决例如连续子数组之类的问题。

二维前缀和

具体实施步骤
1 .预处理二维数组
S(i , j) = S(i - 1 , j) + S(i , j - 1)- S( i - 1 , j - 1) +map[ i ][j]
2.实践求某个矩形/正方形区域内的数字和
核心思想 : 还是拼凑出我们想求的区域的面积(这里的面积就是我们所求区域的数字和),通过之前的 预处理操作
S = S(x1 - 1 + a , y1 - 1 + b) - S(x1 - 1 + a , y1- 1) - S(x1 - 1 , y1 - 1 + b) + S(x1 - 1 , y1 - 1 )

2036: [蓝桥杯2022初赛] 统计子矩阵 (枚举题型的优化解)

链接
未ac 只过了80%

package test;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int a = in.nextInt();
        int b = in.nextInt();
        int k = in.nextInt();
        long[][] arr = new long[a+1][b+1];
        for(int i = 1;i<=a;i++){
            for(int j = 1;j<=b;j++) {
                arr[i][j] = arr[i-1][j] +arr[i][j-1] - arr[i-1][j-1] + in.nextInt();
            }
        }
        int res=0;

        for(int i = 1;i<=a;i++){
            for(int j = 1;j<=b;j++) {
                for(int m = i;m<arr.length;m++){
                    for(int n = j;n<arr[0].length;n++) {
                        if( arr[m][n] - arr[m][j-1] - arr[i-1][n] + arr[i-1][j-1] <=k){
                            res++;
                        }else{
                            break;
                        }
                    }
                }
            }
        }
        System.out.println(res);
    }

}

逆序对问题

D 蓝桥杯历届试题-小朋友排队

求逆序对的问题
解法:

  1. 树形数组
  2. 归并排序

归并排序模板:

class Solution {
    static int count=0;
    public static void main(String[] args) {
        int[] arr = new int[]{4,5,6,7};
        System.out.println(reversePairs(arr));
    }
    public static int reversePairs(int[] nums) {
        sort(nums,0,nums.length-1);
        return count;
    }
    public static void sort(int[] nums,int l,int r){
        if(l>=r){
            return;
        }
        int med = l+(r-l)/2;//(r+l)/2  是否可能越界
        sort(nums,l,med);
        sort(nums,med+1,r);

        if(nums[med]>nums[med+1]){
            merge(nums,l,med,r);
        }
    }
    public static void merge(int[] nums,int l,int med,int r){
        int[] temp = new int[nums.length];
        System.arraycopy(nums,l,temp,l,r-l+1);
        int i=l,j=med+1;
        for(int k=l;k <= r;k++){//temp是旧值 arr是新值跟随移动
            if(i>med){
                nums[k] = temp[j++];
            }
            else if(j>r){
                nums[k]=temp[i++];
            }
            else if(temp[i]<=temp[j]){
                nums[k]=temp[i++];
            }
            else if(temp[i]>temp[j]){
                nums[k]=temp[j++];
                count += med-i+1;
            }
        }
    }
}
import java.util.Scanner;


public class Main {

    public static person[] Child;
    public static person[] temp;

    static class person{
        public int high;
        public int count;
        public person(int high){
            this.high=high;
        }

    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int num = scanner.nextInt();//人数
        Child = new person[num];
        temp = new person[num];
        for(int i=0;i<num;i++){
            int a = scanner.nextInt();
            Child[i] = new person(a);
        }
        sort(0,num-1);
        long res = 0;
        for (int i = 0; i < num; i++) res += cal(Child[i].count);
        System.out.println(res);
    }

    private static long cal(int k) {
        return ((long) k * (k + 1)) / 2;
    }

    public static void sort(int l,int r){
        if(l>=r) return;
        int med = l+(r-l)/2;
        sort(l,med);
        sort(med+1,r);
        merge(l,med,r);
    }

    public static void merge(int l,int med,int r){
        int i = l,j=med+1 , k=l;
        while(i<=med&&j<=r){
            if(Child[i].high>Child[j].high){
                Child[j].count += med-i+1;
                temp[k++] = Child[j++];
            }else{
                temp[k++] = Child[j++];
            }
        }
        while(i<=med&&j>r){
            Child[i].count += r-med;
            temp[k++] = Child[i++];
        }
        while(i>med&&j<=r){
            temp[k++] = Child[j++];
        }
        for (int m = l; m <= r ; m++) {
            Child[m] = temp[m];
        }
    }
}

dfs思想

C K-进制数

dfs思想

import java.util.Scanner;

/*
考虑包含N位数字的K-进制数. 定义一个数有效, 如果其K-进制表示不包含两连续的0.
 */
public class C_1102 {
    static int n;
    static int k;
    static int count=0;
    static int[] temp = new int[20];
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        k = sc.nextInt();
        dfs(0);
        System.out.println(count);
    }

    public static void dfs(int bit){//当前指向的位
        //baseCase
        if(bit==n){
            count++;
            return;
        }
        //对于0——k-1位搜索
        for(int i=0;i<k;i++){
            if((bit==0&&i==0)||(i==0&&temp[bit-1]==0)){
                continue;
            }
            temp[bit]=i;
            dfs(bit+1);
        }
    }
}

技巧题

517. 超级洗衣机(贪心)(维持一个累加和)

对每个当前单位而言 左边最少的支出或盈余 右边最少的支出或盈余

class Solution {
        public static int findMinMoves(int[] machines) {
        int nums =0;
        for(int i : machines){
            nums+=i;
        }
        if(nums%machines.length!=0){
            return -1;
        }
        int n = nums/machines.length;
        int res = 0;
        int leftSum =0;
        for(int i=0;i<machines.length;i++){
            int leftRest = leftSum-i*n;
            int rightRest = (nums-machines[i]-leftSum) - n*(machines.length - i-1) ;
            if(leftRest<0&&rightRest<0){
                res = Math.max(res,Math.abs(leftRest)+Math.abs(rightRest));
            }else{
                res = Math.max(res,Math.max(leftRest,rightRest));
            }
            leftSum += machines[i];
        }

        return res;
    }
}

滑动窗口问题

一维滑动窗口(模板)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值