A(填) 内存计算
在计算机存储中,15.125GB 是多少 MB?
答案提交
- 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
* 注:看清题目,提交整数
System.out.println(15.125 * 1024);
答案:15488
B(填) 二进制数之和
两个二进制数 11110011101 和 1111101001 的和是多少?请用二进制表示,注意在提交的时候不要提交前导 0。
答案提交
- 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个二进制数,在提交答案时只填写这个二进制数,填写多余的内容将无法得分。
方法一:自定义 | 库函数
* 库函数,二进制转整数稍有遗忘:一定要数量使用库函数。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
PrintWriter pw = new PrintWriter(System.out, true); //自动刷新
// int n1 = Integer.valueOf("11110011101", 2);
// int n2 = Integer.valueOf("1111101001", 2);
int n1 = get("11110011101");
int n2 = get("1111101001");
System.out.println(n1 + " " + n2); //1949 1001
System.out.println(Integer.toBinaryString(n1+n2));
}
static int get(String s) {
int rate = 1, res = 0;
for (int i = s.length()-1; i >= 0; i--) {
res += rate * (s.charAt(i) == '1' ? 1 : 0);
rate *= 2;
}
return res;
}
}
答案:101110000110
C(填) 约数个数
1200000 有多少个约数(只计算正约数)。
无用题。
答案:96
D(填) 叶子结点
一棵包含有 2019 个结点的二叉树,最多包含多少个叶结点?
方法一:抽象
如果没有指定树的类型,所以,最多会有 2018 个叶子结点。本题指定是二叉树:
- 排成完全二叉树时叶子节点最多。
- 由公式 n = n 0 + n 1 + 2 ∗ n 2 n = n0 + n1 + 2*n2 n=n0+n1+2∗n2 得,要使 n0 最多,n1 和 n2 必须最少。
- 二叉树有一个性质,即
叶子节点 = 度为 2 的节点数 + 1
,即 n0 = n2 + 1,而完全二叉树中 n1 = 0/1,显然 n1 = 0 时,n0 最多。 - 则 n 2 = ( 2019 − 1 ) / 2 = 1009 n2=(2019-1)/2=1009 n2=(2019−1)/2=1009,故 n 0 = 1009 + 1 = 1010 n0 = 1009 + 1 = 1010 n0=1009+1=1010
注:
- n0:度为 0 的节点会有 0 个子结点。
n1:度为 1 的节点会有 1 个子结点。
n2:度为 2 的节点会有 2 个子结点。
答案:2018
参考链接:https://zhidao.baidu.com/question/37018907.html
https://zhidao.baidu.com/question/1606512639172722827.html
https://zhidao.baidu.com/question/1798769558483406667.html —> 对
E(设计) 数位递增数的个数
一个正整数如果任何一个数位不大于右边相邻的数位,则称为一个数位递增的数,例如 1135 是一个数位递增的数,而 1024 不是一个数位递增的数。给定正整数 n,请问在整数 1 至 n 中有多少个数位递增的数?
输入格式
- 输入的第一行包含一个整数 n。
输出格式
- 输出一行包含一个整数,表示答案。
样例输入
30
样例输出
26
评测用例规模与约定
- 对于 40% 的评测用例,1 <= n <= 1000。
- 对于 80% 的评测用例,1 <= n <= 100000。
- 对于所有评测用例,1 <= n <= 1000000。
方法一:暴力
- 错误分析:对于 80%: 1 0 5 10^5 105,即 10 w 10w 10w, O ( n 2 ) O(n^2) O(n2) 的算法大概运算 ( 1 0 5 ) 2 (10^5)^2 (105)2 次,1s 时限肯定超时。
- 正确分析:由于满足条件的数不会很多,所以暴力可以过,但是保险起见,建议采用方法二。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
PrintWriter pw = new PrintWriter(System.out, true); //自动刷新
int n = sc.nextInt();
int count = 0;
for (int i = 1; i <= n; i++) {
if (check(i))
count++;
}
System.out.println(count);
}
static boolean check(int n) {
char[] s = (n + "").toCharArray();
for (int i = 1; i < s.length; i++) {
if ((s[i-1]-'0') > (s[i]-'0'))
return false;
}
return true;
}
}
复杂度分析
- 时间复杂度: O ( n 2 ) O(n^2) O(n2),
- 空间复杂度: O ( 1 ) O(1) O(1),
F(设计) 单词分段
小明对类似于 hello 这种单词非常感兴趣,这种单词可以正好分为四段,第一段由一个或多个辅音字母组成,第二段由一个或多个元音字母组成,第三段由一个或多个辅音字母组成,第四段由一个或多个元音字母组成。
给定一个单词,请判断这个单词是否也是这种单词,如果是请输出 yes,否则请输出 no。
元音字母包括 a, e, i, o, u,共五个,其他均为辅音字母。
输入格式
- 输入一行,包含一个单词,单词中只包含小写英文字母。
输出格式
- 输出答案,或者为 yes,或者为 no。
样例输入
lanqiao
样例输出
yes
样例输入
world
样例输出
no
评测用例规模与约定
- 对于所有评测用例,单词中的字母个数不超过100。
方法一:分段统计
- 先特判一下。
- 分段处理,最后一定要加上
i == s.length && ...
,因为可能会存在这种样例qeqeq
。
* 算法的缺点:如果要判断 n
段,需要写 n
个 while(...)
,不通用。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static int[] vowel, cons;
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
PrintWriter pw = new PrintWriter(System.out, true); //自动刷新
char[] s = sc.next().toCharArray();
vowel = new int[26]; //存储元音
cons = new int[26]; //存储辅音
for (char c = 'a'; c <= 'z'; c++) {
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
vowel[c-'a']++;
else
cons[c-'a']++;
}
if (check(s)) System.out.println("yes");
else System.out.println("no");
}
private static boolean check(char[] s) {
if (s.length < 4)
return false;
//第一个字符非辅音或者最后一个字母非元音
if (cons[s[0]-'a'] == 0 || vowel[s[s.length-1]-'a'] == 0)
return false;
int i = 0;
boolean a = false, b = false, c = false, d = false;
while (i < s.length && cons[s[i]-'a'] > 0) {
a = true;
i++;
}
while (i < s.length && vowel[s[i]-'a'] > 0) {
b = true;
i++;
}
while (i < s.length && cons[s[i]-'a'] > 0) {
c = true;
i++;
}
while (i < s.length && vowel[s[i]-'a'] > 0) {
d = true;
i++;
}
if (i == s.length && a && b && c && d)
return true;
return false;
}
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),
- 空间复杂度: O ( 1 ) O(1) O(1),
方法二:统计高度和的为 1 的个数
- 元音 vowel 的高度设为 1,辅音 cons 的高度设为 0.
- 最后统计两个字符之间的高度和为 1 的数量是否为 3 即可。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static int[] vowel, cons;
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
PrintWriter pw = new PrintWriter(System.out, true); //自动刷新
char[] s = sc.next().toCharArray();
if (check(s))
System.out.println("yes");
else System.out.println("NO");
}
private static boolean check(char[] s) {
if (s.length < 4)
return false;
if (isVowel(s[0]) || !isVowel(s[s.length-1]))
return false;
int[] arr = new int[s.length];
for (int i = 0; i < s.length; i++) {
if (isVowel(s[i]))
arr[i] = 1;
else
arr[i] = 0;
}
int cnt = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i] + arr[i-1] == 1)
cnt++;
}
return cnt == 3;
}
private static boolean isVowel(char c) {
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),
- 空间复杂度: O ( n ) O(n) O(n),
G(设) 递增三元组的中心
在数列 a [ 1 ] , a [ 2 ] , . . . , a [ n ] a[1], a[2], ..., a[n] a[1],a[2],...,a[n] 中,如果对于下标 i , j , k i, j, k i,j,k 满足 0 < i < j < k < n + 1 0<i<j<k<n+1 0<i<j<k<n+1 且 a [ i ] < a [ j ] < a [ k ] a[i]<a[j]<a[k] a[i]<a[j]<a[k],则称 a [ i ] , a [ j ] , a [ k ] a[i], a[j], a[k] a[i],a[j],a[k] 为一组递增三元组, a [ j ] a[j] a[j] 为递增三元组的中心。
给定一个数列,请问数列中有多少个元素可能是递增三元组的中心。
输入格式
- 输入的第一行包含一个整数 n。
- 第二行包含 n 个整数 a[1], a[2], …, a[n],相邻的整数间用空格分隔,表示给定的数列。
输出格式
- 输出一行包含一个整数,表示答案。
样例输入
5
1 2 5 3 5
样例输出
2
样例说明
a[2] 和 a[4] 可能是三元组的中心。
评测用例规模与约定
- 对于 50% 的评测用例,2 <= n <= 100,0 <= 数列中的数 <= 1000。
- 对于所有评测用例,2 <= n <= 1000,0 <= 数列中的数 <= 10000。
方法一:暴力
n 最大为 1000,所以 O ( n 3 ) O(n^3) O(n3) 算法运行次数大概为 O ( 100 0 3 ) O(1000^3) O(10003),大概 1 0 9 10^9 109 即 10 亿次,肯定超时,所以只能得 50 % 50\% 50% 的分。
for(int i = 0; i < N-2; i++)
for(int j = i+1; j < N-1; j++)
for(int k = j+1; k < N; k++) {
...
}
复杂度分析
- 时间复杂度: O ( n 3 ) O(n^3) O(n3),
- 空间复杂度: O ( 1 ) O(1) O(1),
方法二:优化
不必从某两个端点开始枚举。
- 我们可以在区间
[0, p2]
内判断 p2 位置的数是否是该区间[0, p2]
的最大的数。- 如果是,再从
p2
往后继续寻找一个比arr[p2]
要大的数的下标。 - 否则,枚举下一个区间
[0, p2+1]
- 如果是,再从
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
PrintWriter pw = new PrintWriter(System.out, true); //自动刷新
int N = sc.nextInt();
int[] arr = new int[N];
for (int i = 0; i < N; i++) {
arr[i] = sc.nextInt();
}
int count = 0;
for (int i = 1; i < N; i++) {
boolean up = false;
for (int j = 0; j < i; j++) {
if (arr[j] < arr[i]) {
up = true;
break;
}
}
if (up == false)
continue;
boolean up2 = false;
for (int k = i + 1; k < N; k++) {
if (arr[k] > arr[i]) {
up2 = true;
break;
}
}
if (up && up2)
count++;
}
System.out.println(count);
}
}
复杂度分析
- 时间复杂度: O ( n 2 ) O(n^2) O(n2),
- 空间复杂度: O ( 1 ) O(1) O(1),
H(设) 正整数序列的个数
小明想知道,满足以下条件的正整数序列的数量:
- 第一项为 n;
- 第二项不超过 n;
- 从第三项开始,每一项小于前两项的差的绝对值。
请计算,对于给定的 n,有多少种满足条件的序列。
输入格式
- 输入一行包含一个整数 n。
输出格式
- 输出一个整数,表示答案。答案可能很大,请输出答案除以10000的余数。
样例输入
4
样例输出
7
样例说明
以下是满足条件的序列:
4 1
4 1 1
4 1 2
4 2
4 2 1
4 3
4 4
评测用例规模与约定
- 对于 20% 的评测用例,1 <= n <= 5;
- 对于 50% 的评测用例,1 <= n <= 10;
- 对于 80% 的评测用例,1 <= n <= 100;
- 对于所有评测用例,1 <= n <= 1000。
方法一:暴搜
题目说的是第 3 项小于第 1 和 第 2 项之差的绝对值,第 4 项小于第 2 和 第 3 项之差的绝对值,一次类推,一开始没看懂,hh。递推式为:
- f ( a , b ) = f ( a , b − 1 ) + 1 f(a, b) = f(a, b-1) + 1 f(a,b)=f(a,b−1)+1
- f ( a , b − 1 ) = f ( b − 1 , 1... b − 1 ) + 1 f(a, b-1) = f(b-1,\ 1...b-1) + 1 f(a,b−1)=f(b−1, 1...b−1)+1
- …
怎么用编程语言描述?总不能写 n 个相同的逻辑把,这里直接用递归。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
private static int MOD = 10000;
static long count;
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
int N = sc.nextInt();
for (int i = 1; i <= N; i++) {
dfs(N, i);
}
w.write(count + "");
w.flush();;
}
private static void dfs(int a, int b) {
if (Math.abs(a-b) < 0)
return;
count++;
for (int i = 1; i < Math.abs(a-b); i++) {
dfs(b, i);
}
}
}
复杂度分析
- 时间复杂度: O ( ) O() O(),不怎么会算这种递归的复杂度
- 空间复杂度: O ( ) O() O(),
方法二:记忆化搜索
一般 dfs 的参数有几个,记忆数组就有几维。
* 不完美的 80%:
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
private static int MOD = 10000;
static long count;
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
int N = sc.nextInt();
memo = new long[N+1][N+1];
long res = 0;
for (int i = 1; i <= N; i++) {
res += dfs(N, i);
}
w.write(res + "");
w.flush();;
}
static long[][] memo;
private static long dfs(int a, int b) {
if (memo[a][b] != 0)
return memo[a][b];
long count = 1;
for (int i = 1; i < Math.abs(a-b); i++) {
count += dfs(b, i);
count %= MOD;
}
return memo[a][b] = count;
}
}
复杂度分析
- 时间复杂度: O ( N 3 ) O(N^3) O(N3),N 到 600 的时候,就差不多需要 1s 了
- 空间复杂度: O ( N 2 ) O(N^2) O(N2),
I(设) 杂草丛生
小明有一块空地,他将这块空地划分为 n 行 m 列的小块,每行和每列的长度都为 1。
小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。
这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,这四小块空地都将变为有草的小块。
请告诉小明,k 个月后空地上哪些地方有草。
输入格式
- 输入的第一行包含两个整数 n, m。
- 接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。
- 接下来包含一个整数 k。
输出格式
- 输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。
样例输入
4 5
.g...
.....
..g..
.....
2
样例输出
gggg.
gggg.
ggggg
.ggg.
评测用例规模与约定
- 对于 30% 的评测用例,2 <= n, m <= 20。
- 对于 70% 的评测用例,2 <= n, m <= 100。
- 对于所有评测用例,2 <= n, m <= 1000,1 <= k <= 1000。
方法一:枚举(非 bfs)
枚举 k 次,每一次将草 g
上下的 .
变为 g
,
复杂度分析
- 时间复杂度: O ( ) O() O(),
- 空间复杂度: O ( ) O() O(),
方法一:多源 bfs
首先将所有的草 g
入队,然后 bfs 即可
复杂度分析
- 时间复杂度: O ( ) O() O(),
- 空间复杂度: O ( ) O() O(),
J(设) 组织晚会
小明要组织一台晚会,总共准备了 n 个节目。然后晚会的时间有限,他只能最终选择其中的 m 个节目。
这 n 个节目是按照小明设想的顺序给定的,顺序不能改变。
小明发现,观众对于晚上的喜欢程度与前几个节目的好看程度有非常大的关系,他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。
小明给每个节目定义了一个好看值,请你帮助小明选择出 m 个节目,满足他的要求。
输入格式
- 输入的第一行包含两个整数 n, m ,表示节目的数量和要选择的数量。
- 第二行包含 n 个整数,依次为每个节目的好看值。
输出格式
- 输出一行包含 m 个整数,为选出的节目的好看值。
样例输入
5 3
3 1 2 5 4
样例输出
3 5 4
样例说明
选择了第1, 4, 5个节目。
评测用例规模与约定
- 对于 30% 的评测用例,1 <= n <= 20;
- 对于 60% 的评测用例,1 <= n <= 100;
- 对于所有评测用例,1 <= n <= 100000,0 <= 节目的好看值 <= 100000。
尝试一:二次排序(错误)
血亏:第一眼的思路就是这个,而且还去实现了,测试样例也输出正确,但是一分都得不了。假如有一组数据为:
10 7
15 56 59 41 69 66 6 76 15 50
按照这样的选法,选出来的数据就是:
56 59 41 69 66 76 50
观察一下,会发现:第一个选 56 是错的,因为第一个节目应该选 59 才是满足观众的需求的,尽管好看度总和并不是最大,这题毕竟不是求好看度总和,观众认为前几个好看,整体就好看…
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
int N = sc.nextInt();
int m = sc.nextInt();
int[] arr = new int[N];
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < N; i++) {
arr[i] = sc.nextInt();
map.put(arr[i], i);
}
List<Pair> list = new ArrayList<>();
Arrays.sort(arr);
for (int i = N-1; i >= N-m; i--) {
int idx = map.get(arr[i]);
list.add(new Pair(idx, arr[i]));
}
Collections.sort(list, (e1, e2)->e1.idx - e2.idx);
for (Pair p : list) {
w.write(p.n + " ");
}
w.flush();
}
static class Pair {
int idx, n;
public Pair(int _idx, int _n) {
idx = _idx;
n = _n;
}
}
}
复杂度分析
- 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),
- 空间复杂度: O ( n ) O(n) O(n),
方法二:枚举
题目说:观众希望第一个节目尽可能好看”并希望“第二个节目尽可能好看,所以我们只能在 [0, n-m]
中选一个最好看的,然后从 [lastMaxIdx+1, n-m+1]
中选最大,更新最大值下标 lastMaxIdx
…
只能得 60% 分,数据最大为 100000,即 1 0 5 10^5 105, O ( 1 0 5 ) 2 O(10^5)^2 O(105)2 = O ( 1 0 10 ) O(10^{10}) O(1010),1s 时限是超时的, 1 0 5 10^5 105 的数据复杂度至少 O ( n l o g n ) O(nlogn) O(nlogn)。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
int n = sc.nextInt();
int m = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int p1 = 0, p2 = n-m, pm = p1;
while (p1 < p2) {
while (p1 < p2) {
if (arr[++p1] > arr[pm])
pm = p1;
}
w.write(arr[pm] + " ");
p1 = pm + 1;
p2++;
if (p2 >= n)
break;
}
while (p2 < n) { //指针重合证明
w.write(arr[p2++] + " ");
}
w.flush();
}
}
复杂度分析
- 时间复杂度: O ( n 2 ) O(n^2) O(n2),
- 空间复杂度: O ( 1 ) O(1) O(1),