蓝桥杯知识点复习

输入输出

  1. 输入:

需要导入包:import java.util.Scanner;之后Scanner cin = new Scanner(System.in);

之后可以用cin对象配合.nextXXXX()方法接受数据了XXX可以为Int、Float、Double、空(String类型,遇到空格结束)、Line(Sting类型,读取一行)

最后cin.close();

  1. 输出:

System.out.printf("%m.nd",a);

暴力枚举

数学

  1. 进制转换:

1.十进制转其他进制:Integer.toString(k,r) ,将十进制的数k转换为r进制的数。返回一个String。

System.out.println(Integer.toBinaryString(k)); //转二进制

System.out.println(Integer.toOctalString(k)); //转八进制

System.out.println(Integer.toHexString(k)); //转十六进制

System.out.println(Integer.toString(k,r)); //转r进制

System.out.println(Integer.toString(k,r)); //转r进制

System.out.println(Integer.toString(k,r)); //转r进制

2.其他进制转十进制:Integer.parseInt(str,r) ,将r进制的数字字符串str转换为十进制,并返回十进制的数。

System.out.println(Integer.parseInt("10001",2));

System.out.println(Integer.parseInt("21",8));

System.out.println(Integer.parseInt("11",16));

  1. 质数筛法:输入一个整数 n,求小于这个整数的所有质数。

定义一个长度为 n 的 boolean 数组,true 表示是质数,false 表示不是质数。初始均为 true。

代码:

public static boolean isPrime(int n){

    int [] arr = new int[n+1];

    // 1:质数   0:非质数

    Arrays.fill(arr,1);



    for(int i = 2; i <= n; i++){

        if(arr[i] == 1){

            // 将i的倍数去除掉

            for(int j = i+i; j <= n; j += i){

                arr[j] = 0;

            }

        }

    }

    return arr[n] == 1 ? true : false;

}   

排序算法

  1. 快速排序

基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

代码:

public static void quickSort(int[] arr, int left, int right) {

        int l = left, r = right;

        int pivot = arr[(l + r) / 2];

       

        while(l < r) {

            while(arr[l] < pivot) {

                l++;

            }

           

            while(arr[r] > pivot) {

                r--;

            }

           

            if(r == l) {

                break;

            }

           

            int temp = arr[l];

            arr[l] = arr[r];

            arr[r] = temp;

           

            if(arr[l] == pivot) {

                r -= 1;

            }

           

            if(arr[r] == pivot) {

                l += 1;

            }

        }

       

        if(left < right) {

            quickSort(arr, left, l - 1);

            quickSort(arr, r + 1, right);

        }

    }
  1. 归并排序

先将待排序的数组不断拆分,直到拆分到区间里只剩下一个元素的时候。不能再拆分的时候。这个时候我们再想办法合并两个有序的数组,得到长度更长的有序数组。当前合并好的有序数组为下一轮得到更长的有序数组做好了准备。一层一层的合并回去,直到整个数组有序。

代码:

public static void mergeSort(int[] arr, int left, int right, int[] temp) { //总方法

    if (left < right) {

        int mid = (left + right) / 2;

        mergeSort(arr, left, mid, temp);

        mergeSort(arr, mid + 1, right, temp);

        merge(arr, left, mid, right, temp);

    }

}

public static void merge(int[] arr,int left,int mid,int right,int[] temp){ //合并算法

    int i = left;

    int j = mid+1;

    int t = 0;

    while (i<=mid && j<=right){

      if(arr[i]<=arr[j]){

        temp[t] = arr[i];

        t += 1;

        i += 1;

      }else {

        temp[t] = arr[j];

        t += 1;

        j += 1;

      }

    }

    while(i<=mid){//将左边剩余元素填充进temp中

      temp[t] = arr[i];

      t += 1;

      i += 1;

    }

    while(j<=right){//将右序列剩余元素填充进temp中

      temp[t] = arr[j];

      t += 1;

      j += 1;

    }

    t = 0;

    int tempLeft = left;

    while(tempLeft <= right){

      arr[tempLeft] = temp[t];

      t += 1;

      tempLeft += 1;

    }

}
  1. 插入排序

基本思想是:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。

代码:

  1. 堆排序:

思想:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。

代码;

public class HeapSort {

    public static void main(String[] args) {

        int arr[] = {4, 6, 8, 5, 9};

        heapSort(arr);

    }

 

    public static void heapSort(int arr[]) {

        int temp = 0;

        for (int i = arr.length / 2 - 1; i >= 0; i--) {

            adjustHeap(arr, i, arr.length);

        }

        for (int j = arr.length - 1; j > 0; j--) {

            temp = arr[j];

            arr[j] = arr[0];

            arr[0] = temp;

            adjustHeap(arr, 0, j);

 

        }

    }

     * @param arr    待调整的数组

     * @param i      表示非叶子结点在数组中索引

     * @param length 表示对多少个元素继续调整,length 是在逐渐的减少

    public static void adjustHeap(int arr[], int i, int length) {

        int temp = arr[i];//先取出当前元素的值,保存在临时变量

        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {

            if (k + 1 < length && arr[k] < arr[k + 1]) {

                k++;

            }

            if (arr[k] > arr[i]) {

                arr[i] = arr[k];

                i = k;

            } else {

                break;

            }

        }

        arr[i] = temp;

    }

}

递归

  1. DFS

基本思想:

1.访问初始结点v,并标记结点v为已访问。

2.查找结点v的第一个邻接结点w。

3.若w存在,则继续执行4,如果w不存在,则回到第1步,将从v的下一个结点继续。

4.若w未被访问,对w进行深度优先遍历递归(即把w当做另一个v,然后进行步骤123)。

5.查找结点v的w邻接结点的下一个邻接结点,转到步骤3。

public class Main {

        private List<String> vertexList;//用于存储顶点的集合

        private int[][] edges;//用来保存图对应的邻接矩阵

        private int edgeOfNums;//显示边的个数

        private boolean[] isVisited;

        //===========深度优先遍历的方法===========

        public int getNextNeighbor(int v1,int v2) {

            for (int i = v2 +1;i < vertexList.size();i++) {

                if (edges[v1][i] == 1) {

                    return i;

                }

            }

            return -1;

        }

        //3.深度优先算法DFS

        private void DFS(boolean[] isVisited,int i) {

            System.out.print(getVertexByIndex(i)); //访问

            isVisited[i] = true;

            int w = getNextNeighbor(i, i);

            while (w != -1) {

                if (!isVisited[w]) {

                    DFS(isVisited,w);

                }

                w = getNextNeighbor(i,w);

            }

        }

        public void DFS() {

            isVisited = new boolean[vertexList.size()];

            for (int i = 0; i < getVertexNum(); i++) {

                if (!isVisited[i]) {

                    DFS(isVisited,i);

                }

            }

        }

  1. BFS

基本思想:

1.访问初始结点v并标记结点v为已访问。

2.结点v入队列

3.当队列非空时,继续执行,否则算法结束。

4.出队列,取得队头结点u。

5.查找结点u的第一个邻接结点w。

6.若结点u的邻接结点w不存在,则转到步骤3;否则循环执行以下三个步骤:

6.1 若结点w尚未被访问,则访问结点w并标记为已访问。

6.2 结点w入队列

6.3 查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6。

private void BFS(boolean[] isVisited,int i) {

        int u;//表示队列的头结点对应的下标

        int w;//表示邻接结点的下标

        LinkedList queue = new LinkedList();

        System.out.print(i); //访问

        isVisited[i] = true;

        queue.addLast(i);

        while (!queue.isEmpty()) {  

            u = (Integer)queue.removeFirst();

            w = getNextNeighbor(u);

            while (w != -1) {//说明w(邻接结点存在)

                if (!isVisited[w]) {

                    System.out.print(i); //访问

                    isVisited[w] = true;

                    queue.addLast(w);

                }

                w = getNextNeighbor(u,w);

            }

        }

    }

    public void BFS() {

        isVisited = new boolean[vertexList.size()];

        for (int i = 0; i < getVertexNum(); i++) {

            if (!isVisited[i]) {

                BFS(isVisited,i);

            }

        }

    }

数据结构

  1. 并查集:
//并查集(路径压缩)

//par数组用来存储根节点,par[x]=y表示x的根节点为y

static int[] par = new int[10005];

//初始化

public static void init(int n){

    for (int i = 1; i <= n; i++) {

        par[i]=i;

    }

}

//查找x所在集合的根

public static int find(int x){

    if(par[x]!=x) par[x]=find(par[x]); //递归返回的同时压缩路径

    return par[x];

}

//合并x与y所在集合

public static void unite(int x,int y){

    int tx = find(x);

    int ty = find(y);

    if(tx!=ty){ //不是同一个根,即不在同一个集合,就合并

        par[tx]=ty;

    }

}

  1. 线段树:
public static int[] a = new int[maxd]; //原数组

public static int[] tree = new int[maxd*4]; //树存储

//初始化建树

public static void build(int p,int l,int r){

    if(l==r){

        tree[p]=a[l];

        return ;

    }

    int mid = (r+l)/2; // 防止爆范围

    build(p*2,l,mid); //左子树

    build(p*2+1,mid+1,r); //右子树

    tree[p]=tree[p*2]+tree[p*2+1];

}

//将x位置的值加上num

public static void update(int p,int l,int r,int x,int num){

    if(x>r||x<l) return ;

    if(l==r&&l==x){ //找到x位置

        tree[p] += num; //灵活变

        return ;

    }

    int mid = (r+l)/2;

    update(p*2,l,mid,x,num);

    update(p*2+1,mid+1,r,x,num);

    tree[p]=tree[p*2]+tree[p*2+1];

}

//查询区间和

public static int query(int p,int l, int r ,int x, int y){

    if(x<=l&&r<=y) return tree[p];

    if(x>r||y<l) return 0;

    int mid = (r+l)/2;

    int sum = 0;

    sum+=query(p*2,l,mid,x,y);

    sum+=query(p*2+1,mid+1,r,x,y);

    return sum;

}

动态规划

  1. 背包问题:
public static int[] dp = new int[maxd]; //最大价值

public static int[] w = new int[maxd]; //每件物品的体积

public static int[] v = new int[maxd]; //每件物品的价值

public static int g = 1

1)01背包问题:

int n = nextInt(); //n件物品

int m = nextInt(); //给出的体积

for(int i=1;i<=n;++i) {

    w[i] = nextInt();

    v[i] = nextInt();

}

for(int i=1;i<=n;++i){

    for(int j=m;j>=w[i];--j){ //与完全背包的区别

        dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]);

    }

}

  1. 完全背包:
for(int i=1;i<=n;++i){

    for(int j=w[i];j<=m;++j){ //与01背包的区别

        dp[j]=Math.max(dp[j],dp[j-w[i]]+v[i]);

    }

}
  1. 多重背包:
//朴素算法

for(int i=1;i<=n;++i){

    for(int j=m;j>=w[i];--j){

        for (int k = 0; k <= s[i] && k * w[i] <= j; k++) {

            dp[j] = Math.max(dp[j], dp[j - k*w[i]] + k*v[i]);

        }

    }

}

//二进制优化

int n = nextInt();

int m = nextInt();

for(int i=1;i<=n;++i){

    int a = nextInt(); //体积

    int b = nextInt(); //价值

    int c = nextInt(); //数量

    for(int j=1;j<=c;j<<=1){

        w[g]=j*a;

        v[g++]=j*b;

        c-=j;

    }

    if(c>0){

        w[g]=c*a;

        v[g++]=c*b;

    }

}

for(int i=1;i<=g;++i){

    for(int j=m;j>=w[i];--j){

        dp[j]=Math.max(dp[j],dp[j-w[i]]+v[i]);

    }

}

其他

  1. 二分查找:

代码:

public static int commonBinarySearch(int[] arr,int key){

        int low = 0;

        int high = arr.length - 1;

        int middle = 0;         //定义middle

        if(key < arr[low] || key > arr[high] || low > high){

            return -1;              

        }

        while(low <= high){

            middle = (low + high) / 2;

            if(arr[middle] > key){

                //比关键字大则关键字在左区域

                high = middle - 1;

            }else if(arr[middle] < key){

                //比关键字小则关键字在右区域

                low = middle + 1;

            }else{

                return middle;

            }

        }

       

        return -1;      //最后仍然没有找到,则返回-1

    }

  1. 哈希表:

// 创建 HashMap 对象 Sites

HashMap<Integer, String> Sites = new HashMap<Integer, String>();

// 添加键值对

Sites.put(1, "Google");

HasgMap常用方法:

  1. boolean remove() 方法用于删除hashMap 中指定键 key 对应的键值对(key-value)

2.put() 方法将指定的键/值对插入到 HashMap 中。如果插入的 key 对应的 value 已经存在,则执行 value 替换操作,返回旧的 value 值,如果不存在则执行插入,返回 null

3.get() 方法获取指定 key 对应对 value回与指定 key 所关联的 value。

贪心

图论

  1. 最短路径:

Floyd算法:

public class FloydAlgorithm {

    public static void main(String[] args) {

        // 测试看看图是否创建成功

        char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };

        //创建邻接矩阵

        int[][] matrix = new int[vertex.length][vertex.length];

        final int N = 65535;

        matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };

        //创建 Graph 对象

        Graph graph = new Graph(vertex.length, matrix, vertex);

        //调用弗洛伊德算法

        graph.floyd();

    }

}



// 创建图

class Graph {

    private char[] vertex; // 存放顶点的数组

    private int[][] dis; // 保存,从各个顶点出发到其它顶点的距离,最后的结果,也是保留在该数组

    private int[][] pre;// 保存到达目标顶点的前驱顶点

    // 构造器

    /**

     *

     * @param length

     *            大小

     * @param matrix

     *            邻接矩阵

     * @param vertex

     *            顶点数组

     */

    public Graph(int length, int[][] matrix, char[] vertex) {

        this.vertex = vertex;

        this.dis = matrix;

        this.pre = new int[length][length];

        // 对pre数组初始化, 注意存放的是前驱顶点的下标

        for (int i = 0; i < length; i++) {

            Arrays.fill(pre[i], i);

        }

    }

    //弗洛伊德算法, 比较容易理解,而且容易实现

    public void floyd() {

        int len = 0; //变量保存距离

        //对中间顶点遍历, k 就是中间顶点的下标 [A, B, C, D, E, F, G]

        for(int k = 0; k < dis.length; k++) { //

            //从i顶点开始出发 [A, B, C, D, E, F, G]

            for(int i = 0; i < dis.length; i++) {

                //到达j顶点 // [A, B, C, D, E, F, G]

                for(int j = 0; j < dis.length; j++) {

                    len = dis[i][k] + dis[k][j];// => 求出从i 顶点出发,经过 k中间顶点,到达 j 顶点距离

                    if(len < dis[i][j]) {//如果len小于 dis[i][j]

                        dis[i][j] = len;//更新距离

                        pre[i][j] = pre[k][j];//更新前驱顶点

                    }

                }

            }

        }

    }

}

  1. 最小生成树:

Prim算法基本思想:

代码:

public void prim(MGraph graph, int v) { //从v开始访问

        //visited[] 标记结点(顶点)是否被访问过

        int visited[] = new int[graph.verxs];

        //把当前这个结点标记为已访问

        visited[v] = 1;

        int min_weight - 0;

        //h1 和 h2 记录两个顶点的下标

        int h1 = -1;

        int h2 = -1;

        int minWeight = 10000;

        for(int k = 1; k < graph.verxs; k++) {//找到n-1条边

            //这个是确定每一次生成的子图 ,和哪个结点的距离最近

            for(int i = 0; i < graph.verxs; i++) {// i结点表示被访问过的结点

                for(int j = 0; j< graph.verxs;j++) {//j结点表示还没有访问过的结点

                    if(visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < minWeight)

                        minWeight = graph.weight[i][j];

                        h1 = i;

                        h2 = j;

                    }

                }

            }

            //找到一条边是最小h1->h2

            min_weight += minWeight;

            //将当前这个结点标记为已经访问

            visited[h2] = 1;

            //minWeight 重新设置为最大值 10000

            minWeight = 10000;

        }

       

}

String常用方法

  1. String substring(int beginIndex, int endIndex):返回字符串的子字符串begin,end];
  2. String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分字符串。 . 、 $、 | 和 * 等转义字符,必须得加 \\,多个分隔符,可以用 | 作为连字符

Math常用方法

  1. int max(int a, int b):返回最大值
  2. round() 方法返回一个最接近的 int、long 型值,四舍五入。
  3. double pow(double base, double exponent):返回第一个参数的第二个参数次方

StringBuilder

1.String substring(int start, int end):返回一个新的 String,它包含此序列当前所包含的字符子序列。

Arrays常用方法

  1. public static void sort(Object[] a):对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
  2. public static void fill(int[] a, int val):将指定的 int 值分配给指定 int 型数组指定范围中的每个元素

StringBuilder

  1. StringBuilder append(Object o) //将指定 Object类型加入这个序列。
  2. StringBuilder reverse() //导致该字符序列被序列的相反代替。
  3. String toString() //返回表示此顺序中的数据的字符串
  4. int length() //返回长度(字符数)。实际大小。
  5. StringBuilder deleteCharAt(int index) //删除 char在这个序列中的指定位置。

常用数据容器

  1. ArrayList:(链表)
  1. 创建:List<Integer> list = new ArrayList<Integer>();
  2. Boolean  add(E e):将指定的元素追加到此列表的末尾(可选操作)
  3. E get(int index):返回此列表中指定位置的元素。
  4. int size()返回此列表中的元素数。
  5. boolean contains(Object o)如果此列表包含指定的元素,则返回 true
  6. get() 方法通过索引值获取动态数组中的元素。
  1. Stack:(栈)
  1. 创建:Stack<Integer> s = new Stack<Integer>();
  2. E peek()查看栈顶元素。
  3. E pop()删除栈顶元素,并将该元素作为返回值返回。
  4. E push(E item)添加元素到堆栈的顶部
  1. LinkedList(队列):
  1.  LinkedList<String> sites = new LinkedList<String>();创建
  2. public void addLast(E e) 元素添加到尾部。
  3. public E getFirst() 返回第一个元素。
  4. public E removeFirst() 删除并返回第一个元素。
  5. boolean isEmpty()

日期

(1)Calendar

1. Calendar c = Calendar.getInstance();//默认是当前日期,创建一个代表系统当前日期的Calendar对象

2. public final void set(int year,int month,int date)

3.Calendar.YEAR 年份

Calendar.MONTH 月份

Calendar.DATE 日期

字符串与数字转换

(1)通过包装类的 parseXXX() 方法,可以将字符串转换为想要的基本数据类型:int a = Integer.parseInt(str);

int b = Double.parseDouble(str);

(2) String的 valueOf() 方法:String str1 = String.valueOf(a1);

String str2 = String.valueOf(a2);

二叉树的遍历

  1. 前序遍历:
public List<Integer> preorderTraversal(TreeNode root) {

        Stack<TreeNode> stack = new Stack<TreeNode>();

        List<Integer> res = new ArrayList<Integer>();

        while(root != null || !stack.empty()){

            while(root != null){

                res.add(root.val);

                stack.push(root);

                root = root.left;

            }



            if(!stack.Empty()){

                root = stack.pop();

                root = root.right;

            }

//中序遍历

             while(root != null){

                res.add(root.val);

                stack.push(root);

                root = root.left;

            }



            if(!stack.empty()){

                root = stack.pop();

                root = root.right;

            }

        }

        return res;

    }
  1. 后序遍历:
public List<Integer> postorderTraversal(TreeNode root) {

        List<Integer> res = new ArrayList<Integer>();

        if (root == null) {

            return res;

        }



        Deque<TreeNode> stack = new LinkedList<TreeNode>();

        TreeNode prev = null;

        while (root != null || !stack.isEmpty()) {

            while (root != null) {

                stack.push(root);

                root = root.left;

            }

            root = stack.pop();

            if (root.right == null || root.right == prev) {

                res.add(root.val);

                prev = root;

                root = null;

            } else {

                stack.push(root);

                root = root.right;

            }

        }

        return res;

    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

实名吃香菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值