【2016年蓝桥杯Java-B组省赛题解】

一、煤球数目(找规律)

煤球数目

有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),
....
如果一共有100层,共有多少个煤球?

请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

3 - 1 = 2 ; 6 - 3 = 3 ; 10 - 6 = 4

public class Main {
    public static void main(String[] args) {
        int ans = 20;
        int cnt = 4;
        int before = 10;
        for (int i = 5; i <= 100; i++) {
            cnt++;
            before += cnt;
            ans += before;
        }
        System.out.println(ans);
    }
}

答案:171700

二、生日蜡烛(模拟)

生日蜡烛

某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。

现在算起来,他一共吹熄了236根蜡烛。

请问,他从多少岁开始过生日party的?

请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

模拟

public class Main {
    public static void main(String[] args) {
        int ans = 0;
        for (int i = 1; i <= 50; i++) {
            ans = i;
            for (int j = i + 1; j <= 50; j++) {
                ans += j;
                if (ans == 236) {
                    System.out.println(i);
                    break;
                }
            }
            if (ans == 236) break;
        }
    }
}

答案:26

三、凑算式(全排列、模拟)

凑算式

     B      DEF
A + --- + ------- = 10
     C      GHI
     
(如果显示有问题,可以参见【图1.jpg】)
	 
	 
这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。

比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。

这个算式一共有多少种解法?

注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。

在这里插入图片描述
A * C + B + DEF * C/GHI = C * 10

转换成乘法,避免分数加减
A * C * GHI + B * GHI + DEF * C = C * 10 * GHI

import java.util.LinkedList;

public class Main {
    static LinkedList<Integer> tmp = new LinkedList<>();
    static int[] vis = new int[10];
    static int ans = 0;
    public static void main(String[] args) {
        dfs();
        System.out.println(ans);
    }
    static void dfs() {
        if (tmp.size() == 9) {
            int def = tmp.get(3) * 100 + tmp.get(4) * 10 + tmp.get(5);
            int ghi = tmp.get(6) * 100 + tmp.get(7) * 10 + tmp.get(8);
            int a = tmp.get(0);
            int b = tmp.get(1);
            int c = tmp.get(2);
            if (a * c * ghi + b * ghi + def * c == c * 10 * ghi) {
                ans++;
                System.out.printf("%d %d %d %d %d\n", a, b, c, def, ghi);
            }
            return;
        }
        if (tmp.size() > 9) {
            return;
        }
        for (int i = 1; i <= 9; i++) {
            if (vis[i] == 1) {
                continue;
            }
            vis[i] = 1;
            tmp.add(i);
            dfs();
            tmp.removeLast();
            vis[i] = 0;
        }
    }
}

答案:29

四、五、程序填空题

六、方格填数(全排列、搜索)

方格填数

如下的10个格子
   +--+--+--+
   |  |  |  |
+--+--+--+--+
|  |  |  |  |
+--+--+--+--+
|  |  |  |
+--+--+--+

(如果显示有问题,也可以参看【图1.jpg】)

填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)

一共有多少种可能的填数方案?

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

在这里插入图片描述
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)

   +--+--+--+
   | 5 | 6 | 9 |
+--+--+--+--+
| 1 | 4 | 7 | 10 |
+--+--+--+--+
| 2 | 3 | 8 |
+--+--+--+

按照上面的顺序,生成全排列填数。关键在于check判断条件。

import java.util.LinkedList;

public class Main {
    static int ans = 0;
    static LinkedList<Integer> tmp = new LinkedList<>();
    static int[] vis = new int[10];
    public static void main(String[] args) {
        // 先把0-9的全排列求出来,然后看check
        dfs();
        System.out.println(ans);
    }
    static void dfs() {
        if (tmp.size() == 10) {
            int a = tmp.get(0);
            int b = tmp.get(1);
            int c = tmp.get(2);
            int d = tmp.get(3);
            int e = tmp.get(4);
            int f = tmp.get(5);
            int g = tmp.get(6);
            int h = tmp.get(7);
            int i = tmp.get(8);
            int j = tmp.get(9);
            boolean flag = true;
            if (Math.abs(a - b) == 1 || Math.abs(b - c) == 1 || Math.abs(c - d) == 1 || Math.abs(a - d) == 1
            || Math.abs(a - c) == 1 || Math.abs(b - d) == 1 || Math.abs(a - e) == 1 || Math.abs(d - e) == 1
            || Math.abs(e - f) == 1 || Math.abs(d - f) == 1 || Math.abs(g - f) == 1 || Math.abs(g - e) == 1
            || Math.abs(g - d) == 1 || Math.abs(g - c) == 1 || Math.abs(h - g) == 1 || Math.abs(h - c) == 1
                    || Math.abs(h - d) == 1 || Math.abs(i - f) == 1 || Math.abs(i - g) == 1 || Math.abs(i - j) == 1
                    || Math.abs(j - f) == 1 || Math.abs(j - g) == 1 || Math.abs(j - h) == 1) {
                flag = false;
            }
            if (flag) {
                ans++;
            }
            return;
        }
        if (tmp.size() > 10) {
            return;
        }
        for (int i = 0; i <= 9; i++) {
            if (vis[i] == 1) {
                continue;
            }
            vis[i] = 1;
            tmp.add(i);
            dfs();
            vis[i] = 0;
            tmp.removeLast();
        }
    }
}

答案:1580

看一道之前的题目:寒假作业
在这里插入图片描述
这道题是找1-13排列中的12个数,如果直接暴力搜索,时间开销很大,所以可以通过剪枝缩减时间,第一个等式不满足了就不用往下找了。

import java.util.LinkedList;

public class Main {
    static LinkedList<Integer> tmp = new LinkedList<>();
    static int ans = 0;
    static int[] vis = new int[14];
    public static void main(String[] args) {
        dfs();
        System.out.println(ans);
    }
    static void dfs() {
        // 剪枝
        if (tmp.size() == 3 && tmp.get(0) + tmp.get(1) != tmp.get(2)) {
            return;
        }
        // 剪枝
        if (tmp.size() == 6 && tmp.get(3) - tmp.get(4) != tmp.get(5)) {
            return;
        }
        if (tmp.size() == 12) {
            if (tmp.get(0) + tmp.get(1) == tmp.get(2) && tmp.get(3) - tmp.get(4) == tmp.get(5)
            && tmp.get(6) * tmp.get(7) == tmp.get(8) && tmp.get(9) == tmp.get(10) * tmp.get(11)) {
                System.out.println(tmp);
                ans++;
            }
                return;
        }
        if (tmp.size() > 12) {
            return;
        }
        for (int i = 1; i <= 13; i++) {
            if (vis[i] == 1) {
                continue;
            }
            vis[i] = 1;
            tmp.add(i);
            dfs();
            tmp.removeLast();
            vis[i] = 0;
        }
    }
}

答案:64
做了这道题,一定要学会之后在进行暴力搜索时,学会剪枝。

七、※※※剪邮票(搜索、连通性检测)、※※剪格子(n选m全排列(去重))

剪邮票

如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。

请你计算,一共有多少种不同的剪取方法。

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
先看一下剪格子
在这里插入图片描述
下意识是用dfs解,但是否可行?

暂且不探讨这道题,先来看看DFS的搜索路径,给定3x3格子,从上到下,从左到右依次为0-8,用dfs搜索来看看路径(路径长度为4)如何:

import java.util.LinkedList;

public class Main {
    static LinkedList<Integer> tmp = new LinkedList<>();
    static int ans = 0;
    static int[][] vis = new int[4][4];
    static int[] xx = {-1,1,0,0};
    static int[] yy = {0,0,-1,1};
    public static void main(String[] args) {
        int[][] map = new int[3][3];
        int index = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                map[i][j] = index;
                index++;
            }
        }
        vis[0][0] = 1;
        tmp.add(map[0][0]);
        dfs(map, 0, 0);
    }
    static void dfs(int[][] map, int x, int y) {
        if (tmp.size() == 4) {
            System.out.println(tmp);
            return;
        }
        for (int i = 0; i < 4; i++) {
            int tmpx = xx[i] + x;
            int tmpy = yy[i] + y;
            if (tmpx < 0 || tmpy < 0 || tmpx >= 3 || tmpy >= 3 || vis[tmpx][tmpy] == 1) {
                continue;
            }
            vis[tmpx][tmpy] = 1;
            tmp.add(map[tmpx][tmpy]);
            dfs(map, tmpx, tmpy);
            tmp.removeLast();
            vis[tmpx][tmpy] = 0;
        }
    }
}

规定从左上角0出发,得到如下结果:
在这里插入图片描述
在这里插入图片描述
把图画出来,会发现,dfs遍历的结果没有T字型!,例如:0124,这是为什么?DFS是一搜到底,再往回回溯,0124这种情况是遍历不到的,它要么走012到5,要么走01到4,不可能有从01到4再到2,或者01到2再到4。所以如果这种题用dfs遍历去解,肯定是错误的!

如果用BFS,会是怎样的遍历路径?

import java.util.LinkedList;
import java.util.Queue;

class node {
    int x, y;
    LinkedList<Integer> anser;
    node() {};
    node(int x, int y) {this.x = x; this.y = y;}
}
public class Main {
    static int ans = 0;
    static int[][] vis = new int[4][4];
    static int[] xx = {-1,1,0,0};
    static int[] yy = {0,0,-1,1};
    public static void main(String[] args) {
        int[][] map = new int[3][3];
        int index = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                map[i][j] = index;
                index++;
            }
        }
        vis[0][1] = 1;
        Queue<node> Q = new LinkedList<>();
        LinkedList<Integer> start = new LinkedList<>();
        node b = new node(0, 1);
        b.anser = start;
        b.anser.add(map[0][1]);
        // 开始结点装入Q
        Q.offer(b);
        while (!Q.isEmpty()) {
            node temp = Q.poll();
            for (int i = 0; i < 4; i++) {
                node tmp = new node();
                tmp.x = temp.x + xx[i];
                tmp.y = temp.y + yy[i];
                if (tmp.x < 0 || tmp.y < 0 || tmp.x >= 3 || tmp.y >= 3 || vis[tmp.x][tmp.y] == 1) {
                    continue;
                }
                vis[tmp.x][tmp.y] = 1;
                tmp.anser = temp.anser;
                tmp.anser.add(map[tmp.x][tmp.y]);
                System.out.println(tmp.anser);
                Q.offer(tmp);
            }
        }
    }
}

在这里插入图片描述
分析代码下面代码可以知道:
在这里插入图片描述
每次都是把当前结点四个方向可能的值,加入队列中,队列是先进先出,所以会优先把当前结点的四个方向遍历完再接着遍历,而不是和dfs一样,一直深入的遍历。一定要把DFS和BFS的遍历方向搞清楚。

回到之前的题目,如果按照dfs方式,可以写出下列代码,由于测试样例没有考虑完全(没有T字型裁剪),所以导致普通的dfs可以通过测试。

import java.util.LinkedList;
import java.util.Scanner;

public class Main {
    static LinkedList<Integer> tmp = new LinkedList<>();
    static int ans = 99;
    static int m, n;
    static int[][] vis = new int[20][20];
    static int[][] map = new int[20][20];
    static int[] xx = {-1,1,0,0};
    static int[] yy = {0,0,-1,1};
    static int sum = 0;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        m = scan.nextInt();
        n = scan.nextInt();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                map[i][j] = scan.nextInt();
                sum += map[i][j];
            }
        }
        sum /= 2;
        vis[0][0] = 1;
        dfs(map, 0, 0, map[0][0], 1);
        System.out.println(ans);
    }
    static void dfs(int[][] map, int x, int y, int cnt, int step) {
        if (cnt == sum) {
            ans = Math.min(ans, step);
            return;
        }
        for (int i = 0; i < 4; i++) {
            int tmpx = x + xx[i];
            int tmpy = y + yy[i];
            if (tmpx < 0 || tmpy < 0 || tmpx >= n || tmpy >= m || vis[tmpx][tmpy] == 1) {
                continue;
            }
            vis[tmpx][tmpy] = 1;
            dfs(map, tmpx, tmpy, cnt + map[tmpx][tmpy], step + 1);
            vis[tmpx][tmpy] = 0;
        }
    }
}

上面的代码能通过测试,完全是偶然,回到本题,就必须得考虑T字型剪纸,使用普通的dfs解决本题是不行的,它无法解决T字型问题。

测评样例没有考虑T字形问题
在这里插入图片描述

之前的想法是:以每个点为起点,dfs选5张,再去重,但这是错误的!

正解:枚举所有的5张牌的组合,从12个格子里面抽5个,看它们是不是一个连通块

现在问题转换成求12选5(组合),再check是否连通。

12选5,如果直接求12选5的组合,可能需要先求出12的排列,再选前5个,还需要去重。显然这么做是有问题的,时间开销太大。

换种思路,12选5,只要能够选出5个就行,那么我们用一个一维数组,长度为12,里面有5个1,7个0,5个1代表要选的5个数,我们只用遍历这12个元素,找它们的全排列即可。(每次为1的地方就是剪纸的一种方式)

连通块检测:

    // 连通块检测
    static void dfss(int[][] g, int x, int y) {
        for (int i = 0; i < 4; i++) {
            int tmpx = x + xx[i];
            int tmpy = y + yy[i];
            if (tmpx < 0 || tmpy < 0 || tmpx >= 3 || tmpy >= 4 || g[tmpx][tmpy] == 0) {
                continue;
            }
            g[tmpx][tmpy] = 0;
            dfss(g, tmpx, tmpy);
            // 连通块检测不需要回溯!
        }
    }
......
    		int cnt = 0;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 4; j++) {
                    if (g[i][j] == 1) {
                        g[i][j] = 0;
                        // 连通性检测
                        dfss(g, i, j);
                        cnt++;
                    }
                }
            }
            // 只用了一次遍历,说明它们都是连通的
            if (cnt == 1) {
                ans++;
            }

之前说的12选5,只往里面塞了5个1,但是有多个重复的0,和重复的1,会导致全排列重复,我们需要去重(这里和之前回溯专题很类似)。

注意,dfs不能生成T型剪纸,但是dfs可以检测T型剪纸(就是检测连通块)

import java.util.*;

public class Main {
    static LinkedList<Integer> tmp = new LinkedList<>();
    static int[] vis = new int[13];
    static int[] xx = new int[] {-1,1,0,0};
    static int ans = 0;
    static int[] yy = new int[] {0,0,-1,1};
    public static void main(String[] args) {
        int[] a = new int[] {0,0,0,0,0,0,0,1,1,1,1,1};
        dfs(a);
        System.out.println(ans);
    }
    // 连通块检测
    static void dfss(int[][] g, int x, int y) {
        for (int i = 0; i < 4; i++) {
            int tmpx = x + xx[i];
            int tmpy = y + yy[i];
            if (tmpx < 0 || tmpy < 0 || tmpx >= 3 || tmpy >= 4 || g[tmpx][tmpy] == 0) {
                continue;
            }
            g[tmpx][tmpy] = 0;
            dfss(g, tmpx, tmpy);
            // 连通块检测不需要回溯!
        }
    }
    static void dfs(int[] a) {
        if (tmp.size() == 12) {
            System.out.println(tmp);
            int[][] g = new int[3][4];
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 4; j++) {
                    // 把一维数组转成二维数组
                    if (tmp.get(i * 4 + j) == 1) {
                        g[i][j] = 1;
                    } else {
                        g[i][j] = 0;
                    }
                }
            }
            int cnt = 0;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 4; j++) {
                    if (g[i][j] == 1) {
                        g[i][j] = 0;
                        dfss(g, i, j);
                        cnt++;
                    }
                }
            }
            // 只用了一次遍历,说明它们都是连通的
            if (cnt == 1) {
                ans++;
            }
            // 再用dfs进行连通性检测
            return;
        }
        if (tmp.size() > 12) {
            return;
        }
        for (int i = 0; i < 12; i++) {
            // 全排列去重
            if (i > 0 && a[i] == a[i - 1] && vis[i - 1] == 0) {
                continue;
            }
            if (vis[i] == 1) {
                continue;
            }
            vis[i] = 1;
            tmp.add(a[i]);
            dfs(a);
            tmp.removeLast();
            vis[i] = 0;
        }
    }
}

全排列去重核心代码:

if (i > 0 && a[i] == a[i - 1] && vis[i - 1] == 0) {
   	continue;
}

如果是求子集、组合,去重代码:

if (i > start && nums[i - 1] == nums[i]) {
    continue;
}

搞懂这些,最好是通过画图,debug来理解整个过程,不要死记硬背。
答案:116

八、四平方和(循环剪枝)

在这里插入图片描述
直接四循环会超时,可以变成三循环,确定前三个后,第四个数可以直接算出。这也可以算成剪枝的方案。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        f(n);
    }
    static void f(int n) {
        for (int i = 0; i <= Math.sqrt(n); i++) {
            for (int j = i; j <= Math.sqrt(n); j++) {
                for (int k = j; k <= Math.sqrt(n); k++) {
                    int tmp = (int)Math.sqrt(n - i * i - j * j - k * k);
                    if (n == i * i + j * j + k * k + tmp * tmp) {
                        System.out.printf("%d %d %d %d", i, j, k, tmp);
                        return;
                    }
                }
            }
        }
    }
}

九、※取球博弈(记忆型递归)

在这里插入图片描述
在这里插入图片描述
持有奇数个球的一方获胜,如果两人都是奇数则平局。

对于每堆球N,每个人都有n个取法,加入N大于每种取法的取球数,那么先手取球剩余球数可能为:N - n1,N - n2,N - n3。同样,后手也有三种可能。 对于这种存在重复子问题的情况,考虑使用递归解决,使用递归要明确参数和终止条件。

递归参数无非就是,剩余球数,我有的球数,你有的球数,f(N, me, you),但是要注意,一旦身份互换后,me就变成了you,you就变成了me。

注意博弈问题,会有身份互换,me变成you,you变成me。

可以写出下列递归代码:

import java.util.*;

public class Main {
    static int[] n = new int[3];
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        n[0] = scan.nextInt();
        n[1] = scan.nextInt();
        n[2] = scan.nextInt();
        // 排序方便后续结算
        Arrays.sort(n);
        for (int i = 0; i < 5; i++) {
            int num = scan.nextInt();
            char res = f(num, 0, 0);
            System.out.print(res + " ");
        }
    }

    /**
     * 参数代表当前取球人面临的局面
     * @param num 球的总数
     * @param me 我方持有的数目
     * @param you 对手持有的数目
     * @return
     */
    static char f(int num, int me, int you) {
        // 不够取
        if (num < n[0]) {
            if ((me & 1) == 1 && (you & 1) == 0) {
                // 我是奇数,对手是偶数,我就赢了
                return '+';
            } else if ((me & 1) == 0 && (you & 1) == 1) {
                // 我是偶数,对手是奇数,我就输了
                return '-';
            } else {
                // 都是偶数,或者都是奇数,就平局
                return '0';
            }
        }
        boolean ping = false;
        for (int i = 0; i < 3; i++) {
            if (num >= n[i]) {
                // 注意换位
                // 这里拿到的是对手的输赢情况
                char res = f(num - n[i], you, me + n[i]);
                if (res == '-') {
                    // 对手输了,我们就赢了
                    return '+';
                }
                if (res == '0') {
                    ping = true;
                }
            }
        }
        // 如果能走到这里,那就不存在对手输的情况
        // 那么是否存在平局的情况?
        if (ping) {
            return '0';
        } else {
            // 不存在对手输,也不平,那就是输了
            return '-';
        }
    }
}

上面的代码在球多时,会超时,因为会进行多次重复计算,例如:取球顺序123和取球顺序321,本质是一样的。所以要变成记忆型递归。

不需要考虑最后的me、you的球数,只需要考虑奇偶性即可(这也是为了缩小空间消耗),用三维数组存储已有的状态,改成记忆型递归,只需要在return的地方存储数据,在递归函数开始的地方查找cache。

import java.util.*;

public class Main {
    static int[] n = new int[3];
    static char[][][] cache = new char[1000][2][2];
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        n[0] = scan.nextInt();
        n[1] = scan.nextInt();
        n[2] = scan.nextInt();
        // 排序方便后续结算
        Arrays.sort(n);
        for (int i = 0; i < 5; i++) {
            int num = scan.nextInt();
            char res = f(num, 0, 0);
            System.out.print(res + " ");
        }
    }

    /**
     * 参数代表当前取球人面临的局面
     * @param num 球的总数
     * @param me 我方持有的数目 => 实质关注的是数目的奇偶性
     * @param you 对手持有的数目 => 实质关注的是数目的奇偶性
     * @return
     */
    static char f(int num, int me, int you) {
        // 不够取
        if (num < n[0]) {
            if ((me & 1) == 1 && (you & 1) == 0) {
                // 我是奇数,对手是偶数,我就赢了
                return '+';
            } else if ((me & 1) == 0 && (you & 1) == 1) {
                // 我是偶数,对手是奇数,我就输了
                return '-';
            } else {
                // 都是偶数,或者都是奇数,就平局
                return '0';
            }
        }
        // 如果cache中找到了
        if (cache[num][me][you] != '\0') {
            return cache[num][me][you];
        }
        boolean ping = false;
        for (int i = 0; i < 3; i++) {
            if (num >= n[i]) {
                // 注意换位
                // 这里拿到的是对手的输赢情况

                // 记录的是奇偶情况,如果n[i]是奇数,me拿了之后应该为1 - me(改变奇偶性)
                int tmp = me;
                if (n[i] % 2 != 0) {
                    tmp = 1 - tmp;
                }
                char res = f(num - n[i], you, tmp);
                if (res == '-') {
                    // 对手输了,我们就赢了
                    cache[num][me][you] = '+';
                    return '+';
                }
                if (res == '0') {
                    ping = true;
                }
            }
        }
        // 如果能走到这里,那就不存在对手输的情况
        // 那么是否存在平局的情况?
        if (ping) {
            cache[num][me][you] = '0';
            return '0';
        } else {
            // 不存在对手输,也不平,那就是输了
            cache[num][me][you] = '-';
            return '-';
        }
    }
}

此类博弈类问题,要学会划分状态,一步一步地做。

十、压缩变换(模拟拿一半)

在这里插入图片描述
在这里插入图片描述
先看数据规模,直接模拟肯定超时。(果然,只能拿一半分,对我来说够啦!正解需要区间树,加快寻找不同数的种类数。)

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        Map<Integer, Integer> map = new HashMap<>();
        int n = scan.nextInt();
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = scan.nextInt();
        }
//        如果这个数字没有出现过,刚将数字变换成它的相反数
//        如果数字出现过,则看它在原序列中最后的一次出现后面(且在当前数前面)出现了几种数字
//        用这个种类数替换原来的数字
        int[] ans = new int[n];
        for (int i = 0; i < n; i++) {
            if (!map.containsKey(nums[i])) {
                ans[i] = -nums[i];
            } else {
                int index = map.get(nums[i]);
                int cnt = 0;
                Set<Integer> tmp = new HashSet<>();
                for (int j = index + 1; j < i; j++) {
                    if (tmp.contains(nums[j])) {
                        continue;
                    } else {
                        cnt++;
                        tmp.add(nums[j]);
                    }
                }
                ans[i] = cnt;
            }
            System.out.print(ans[i] + " ");
            map.put(nums[i], i);
        }
    }
}
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@u@

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

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

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

打赏作者

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

抵扣说明:

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

余额充值