JAVA基础算法例题+模板(中)

  • Post author:
  • Post category:java




高精度(整数)


由于java中自带计算高精度的对象,所以没有使用传统的方法来解决高精度问题


  • 高精度加法

    给定两个正整数(不含前导 0),计算它们的和。



    输入格式

    共两行,每行包含一个整数。



    输出格式

    共一行,包含所求的和。



    数据范围

    1≤整数长度≤100000

    • import java.math.BigInteger;
      import java.util.Scanner;
      
      public class Main {
          public static void main(String[] args) {
              Scanner scanner=new Scanner(System.in);
              BigInteger a=scanner.nextBigInteger();
              BigInteger b=scanner.nextBigInteger();
              BigInteger add = a.add(b);
              System.out.println(add);
          }
      }
      

  • 高精度减法

    给定两个正整数(不含前导 0),计算它们的差,计算结果可能为负数。



    输入格式

    共两行,每行包含一个整数。



    输出格式

    共一行,包含所求的差。



    数据范围

    1≤整数长度≤105

    • import java.math.BigInteger;
      import java.util.Scanner;
      
      
      public class Main {
          public static void main(String[] args) {
              Scanner scanner=new Scanner(System.in);
              BigInteger a=scanner.nextBigInteger();
              BigInteger b=scanner.nextBigInteger();
              scanner.close();
              BigInteger subtract = a.subtract(b);
              System.out.println(subtract);
          }
      }
      

  • 高精度乘法

    • 给定两个非负整数(不含前导 0) A 和 B,请你计算 A×B 的值。



      输入格式

      共两行,第一行包含整数 A,第二行包含整数 B。



      输出格式

      共一行,包含 A×B 的值。



      数据范围

      1≤A的长度≤100000,

      0≤B≤10000

    • import java.math.BigInteger;
      import java.util.Scanner;
      
      
      public class Main {
          public static void main(String[] args) {
              Scanner scanner=new Scanner(System.in);
              BigInteger a=scanner.nextBigInteger();
              BigInteger b=scanner.nextBigInteger();
              scanner.close();
              BigInteger multiply = a.multiply(b);
              System.out.println(multiply);
          }
      }
      

  • 高精度除法

    • 给定两个非负整数(不含前导 0) A,B,请你计算 A/B 的商和余数。



      输入格式

      共两行,第一行包含整数 A,第二行包含整数 B。



      输出格式

      共两行,第一行输出所求的商,第二行输出所求余数。



      数据范围

      1≤A的长度≤100000,

      1≤B≤10000,

      B 一定不为 0

    • import java.math.BigInteger;
      import java.util.Scanner;
      
      public class Main{
          public static void main(String[] args) {
              Scanner scanner=new Scanner(System.in);
              BigInteger a=scanner.nextBigInteger();
              BigInteger b=scanner.nextBigInteger();
              scanner.close();
              BigInteger divide = a.divide(b);
              System.out.println(divide);
              System.out.println(a.subtract(divide.multiply(b)));
          }
      }
      
      



前缀和与差分



前缀和

  • 例题一

    • 输入一个长度为n的整数序列。

      接下来再输入m个询问,每个询问输入一对l, r。

      对于每个询问,输出原序列中从第Ⅰ个数到第r个数的和。

      输入格式

      第一行包含两个整数n和m。

      第二行包含n个整数,表示整数数列。

      接下来m行,每行包含两个整数l和r,表示一个询问的区间范围。

      输出格式

      共m行,每行输出一个询问的结果。

      数据范围

      1≤l<r ≤n,

      1≤n, m ≤ 100000,

      —1000≤数列中元素的值≤1000

    • import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      
      
      public class Main {
          public static void main(String[] args) throws IOException {
              BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
              int n,m;
              int[] a=new int[100010];
              int[] s=new int[100010];
              String[] strings=reader.readLine().split(" ");
              n=Integer.parseInt(strings[0]);
              m=Integer.parseInt(strings[1]);
              String[] strings1=reader.readLine().split(" ");
              for (int i = 1; i <=n; i++) {
                  a[i]=Integer.parseInt(strings1[i-1]);
              }
              for (int i = 1; i <=n; i++) {
                  s[i]=s[i-1]+a[i];
              }
              while ((m--)>0){
                  int l,r;
                  String[] strings2=reader.readLine().split(" ");
                  l=Integer.parseInt(strings2[0]);
                  r=Integer.parseInt(strings2[1]);
                  System.out.println(s[r]-s[l-1]);
              }
          }
      }
      
      
  • 例题2

    • 输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数x1,y1,x2,y2,表示一个子矩阵的左上角坐标和右下角坐标。

      对于每个询问输出子矩阵中所有数的和。输入格式

      第一行包含三个整数n, m,q。

      接下来n行,每行包含m个整数,表示整数矩阵。

      接下来q行,每行包含四个整数x1,y1,x2,y2表示一组询问。

      输出格式

      共q行,每行输出一个询问的结果。

      数据范围

      1 ≤n, m ≤1000,1≤q≤200000,1≤1 ≤2≤n,1≤y1≤ 92≤ m,

      —1000≤矩阵内元素的值≤1000

    • 二维数组求解前缀项和(图形理解)

    • 求解s[i] [j]

    • 在这里插入图片描述

    • 求解前缀项和

    • 在这里插入图片描述

    • 题解

    • import java.util.Scanner;
      
      /**
       *
       * 796. 子矩阵的和
       */
      public class Main {
          public static void main(String[] args) {
              Scanner scanner=new Scanner(System.in);
              int n,m,q;
              int[][] a=new int[1010][1010];
              int[][] s=new int[1010][1010];
              n=scanner.nextInt();
              m=scanner.nextInt();
              q=scanner.nextInt();
              for (int i = 1; i <= n; i++) {
                  for (int j = 1; j <= m; j++) {
                      a[i][j]=scanner.nextInt();
                  }
              }
              for (int i = 1; i <= n; i++) {
                  for (int j = 1; j <= m; j++) {
                      // 计算, 结合求解s[i] [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,x2,y1,y2;
                  x1=scanner.nextInt();
                  y1=scanner.nextInt();
                  x2=scanner.nextInt();
                  y2=scanner.nextInt();
                     // 计算, 结合求解前缀项和图来理解
                  System.out.println(s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);
              }
      
          }
      }
      



差分


  • 差分是求前缀和的逆操作,对于原数组a[n],构造出一个数组b[n],使a[n]为b[n]的前缀和。一般用于快速对整个数组进行操作,比如对将a数组中[l,r]部分的数据全部加上c。使用暴力方法的话,时间复杂至少为O(n),而使用差分算法可以将时间复杂度降低到O(1)。


  • 算法思路

    • 拥有数组b[n]后,想要对a数组中所有的数据加上c,只需要将b[1]+c即可,因为a[i]是b[i]的前缀和,a[i]=b[1]+b[1]+b[3]+……+b[i]。b[1]是所有的a[i]都拥有的子元素,将b[0]+c,那么a[n]中所有的数据都会加上c。如果想将a数组中[l,r]部分的数据全部加上c,只需要将b[l]+c,然后b[r+1]-c即可。

      差分操作和前缀和一样数组下标都从1开始。b[l]+c后,l后面的数组都会加c。r后面的数据也会被改变,要改回来就得b[r+1]-c

  • 如何构造b[n]


    • 构造b[n]看起来很难,其实根本就不用刻意去构造它。如果将a数组中[l,r]部分的数据全部加上c看作一次插入操作,那么构造的过程可以看作是将a进行了n次插入操作。第一次在[1,1]的范围插入了a[1],第二次在[2,2]范围插入a[2],第二次在[3,3]范围插入a[3]……,以此类推,进行n次插入后,那么数组a就正好是数组b的前缀和了。
  • 例题一:

    • 输入一个长度为n的整数序列。

      接下来输入m个操作,每个操作包含三个整数l,r,c,表示将序列中[1,r]之间的每个数加上c。请你输出进行完所有操作后的序列。

      输入格式

      第一行包含两个整数n和m。

      第二行包含n个整数,表示整数序列。

      接下来m行,每行包含三个整数l, r,c,表示一个操作。

      输出格式

      共一行,包含n个整数,表示最终序列。

      数据范围

      1 ≤n, m ≤100000,1≤l≤r ≤n,

      -1000≤c≤1000,

      -1000≤整数序列中元素的值≤1000

    • import java.util.Scanner;
      
      public class Main {
          static int  N = 100010;
          public static void main(String[] args) {
              Scanner scanner = new Scanner(System.in);
              int n = scanner.nextInt();
              int m = scanner.nextInt();
              int[] a = new int[N];
              int[] b = new int[N];
              for (int i = 1; i <= n; i++) {
                  a[i] = scanner.nextInt();
              }
              for(int i=1;i<=n;i++) {
                  insert(b, i, i, a[i]);
              }
              while((m--)>0) {
                  int l,r,c;
                  l = scanner.nextInt();
                  r = scanner.nextInt();
                  c = scanner.nextInt();
                  insert(b, l, r, 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]+" ");
              System.out.println();
              scanner.close();
          }
          public static void insert(int[] a,int l,int r,int c) {
              a[l]+=c;
              a[r+1]-=c;
          }
      }
      
      

  • 二维差分

    • 二维差分思路和一维的思路是一样的。区别在于公式不同而已
    • 在这里插入图片描述
  • 例题二:

    输入一个 n 行 m 列的整数矩阵,再输入 q 个操作,每个操作包含五个整数 x1,y1,x2,y2,c,其中 (x1,y1)和 (x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。

    每个操作都要将选中的子矩阵中的每个元素的值加上 c。

    请你将进行完所有操作后的矩阵输出。



    输入格式

    第一行包含整数 n,m,q

    接下来 n 行,每行包含 m 个整数,表示整数矩阵。

    接下来 qq行,每行包含 5 个整数 x1,y1,x2,y2,c,表示一个操作。



    输出格式

    共 n 行,每行 m 个整数,表示所有操作进行完毕后的最终矩阵。



    数据范围

    1≤n,m≤1000

    1≤q≤100000

    1≤x1≤x2≤n

    1≤y1≤y2≤m

    −1000≤c≤1000

    −1000≤矩阵内元素的值≤1000

    • import java.io.*;
      
      /**
       * 798. 差分矩阵
       */
      public class Main {
          public static void main(String[] args) throws IOException {
              BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
              String[] str1 = reader.readLine().split(" ");
              int n = Integer.parseInt(str1[0]);
              int m = Integer.parseInt(str1[1]);
              int q = Integer.parseInt(str1[2]);
              int N = 1010;
              int[][] a = new int[N][N];
              int[][] b = new int[N][N];
              for (int i = 1; i <= n; i++) {
                  String[] str2 = reader.readLine().split(" ");
                  for (int j = 1; j <= m; j++) {
                      a[i][j] = Integer.parseInt(str2[j-1]);
                      insert(b, i, j, i, j, a[i][j]);
                  }
              }
              while (q-- > 0) {
                  String[] str3 = reader.readLine().split(" ");
                  int x1 = Integer.parseInt(str3[0]);
                  int y1 = Integer.parseInt(str3[1]);
                  int x2 = Integer.parseInt(str3[2]);
                  int y2 = Integer.parseInt(str3[3]);
                  int k  =  Integer.parseInt(str3[4]);
                  insert(b, x1, y1, x2, y2, k);
              }
              for (int i = 1; i <= n; i++) {
                  for (int j = 1; j <= m; j++) {
                      b[i][j] += b[i][j - 1] + b[i - 1][j] - b[i - 1][j - 1];
                      System.out.print(b[i][j] + " ");
                  }
                  System.out.println();
              }
              reader.close();
          }
          private static void insert(int[][] b, int x1, int y1, int x2, int y2, int k) {
              b[x1][y1] += k;
              b[x2 + 1][y1] -= k;
              b[x1][y2 + 1] -= k;
              b[x2 + 1][y2 + 1] += k;
          }
      }
      
      



版权声明:本文为weixin_47784657原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。