目前刷题数为 17-20-6.使用的是 java,下面讲解一些我刷过的题目。
先从简单的开始
T8. 找出整型数组中占比超过一半的数
小R从班级中抽取了一些同学,每位同学都会给出一个数字。已知在这些数字中,某个数字的出现次数超过了数字总数的一半。现在需要你帮助小R找到这个数字。
先给出代码如下:
public static int solution(int[] array) {
Map<Integer, Integer> map = new HashMap<>();
for (int i : array) {
if (map.containsKey(i)) {
map.put(i, map.get(i) + 1);
if (map.get(i) + 1 > array.length / 2) {
return i;
}
} else {
map.put(i, 1);
}
}
return 0;
}
最后这个 return 0 其实从逻辑的角度来说是不需要的,因为题目已经告诉我们,一定会有一个且只有一个数字出现的次数超过总数的一半,但是由于代码需要返回值,所以还是需要写着的。这里采用的是 map 来存储,map 中的两个值分别代表对应的数字以及出现的次数。每次给次数加一的时候其实就可以进行一次判断,可以快速跳出。
当然,这里也可以使用数组来实现,即 arr[i]=count,但是这样的话,空间复杂度和时间复杂度都会提高。因为需要遍历整个数组,尽管使用 if 判断来跳出循环,对平均时间复杂度影响也不会很大。
T31. 不同整数的计数问题
小R有一个字符串 word,该字符串由数字和小写英文字母组成。小R想用空格替换每一个不是数字的字符。然后,他希望统计在替换后剩下的整数中,不同整数的数目。
例如,给定字符串 "a123bc34d8ef34",替换后形成的字符串是 " 123 34 8 34",剩下的整数是 "123"、"34"、"8" 和 "34"。不同的整数有三个,即 "123"、"34" 和 "8"。
注意,只有当两个整数的不含前导零的十进制表示不同,才认为它们是不同的整数。
先给出对应的代码如下:
public static int solution(String word) {
Set<Integer> set = new HashSet<>();
for (String split : word.replaceAll("\\D", " ").trim().split(" ")) {
if (split.isEmpty())
continue;
set.add(Integer.parseInt(split));
}
return set.size();
}
按照题目要求,先将传入的字符串中的字符替换为整数,这里采用的是正则表达式的方式。替换完成后使用 trim 去除两边的空格,再根据空格来进行切片得到对应的数字字符串数组。数组中或许会有空的字符,所以开始的时候使用了 isEmpt 进行判空处理。随后使用 set 来保存所有的数字,随后将 set 的长度返回即可。
为什么使用 set?因为题目说了要不同的整数。
为什么不使用 set?因为 String 不会对前导零进行区分,如 1、01、001,会被认为是 3 个不同的数字,与题目不符。
T45. 最少步数归零问题
小R拿到了一个长度为n的数组,其中每个元素都是一个正整数。小R发现每次可以删除某个数组中某个数的一位数字,这样可以逐步将所有数字变为0。他想知道,要将数组中所有数字都变为0,最少需要多少步?
例如:对于数字 103,小R可以选择删除第1位数字,将其变为 3;或者删除第2位数字,变为 13,又或者删除第3位数字,将其变为 10。最终目标是将所有数字都删除为0。
public static int solution(int n, int[] a) {
int result = 0;
for (int num : a)
result += String.valueOf(num).replaceAll("0", "").length();
return result;
}
说实话,我不理解这题为什么会被归为难题,因为这个解法也很简单。题目问每次删除一位数字,多少次后变为 0,那么很明显,数字的位数减去 0 的个数即可,那么只需要先将数字变成字符串,使用字符串的 replaceAll 将 0 去除掉,得到剩下的字符串的长度累加即可。
T340. 使数组全为奇数的问题
小U手中有一个包含 N 个整数的数组 A,它的编号从 0 到 N - 1。小U可以执行一种操作:在任意时刻选择数组中任意奇数索引 i 的元素 A[i] 并将其删除。也就是说,用户可以从数组中删除所有位于奇数索引处的元素。
你的任务是帮助小U判断是否可以通过若干次这样的操作使得数组 A 中剩下的所有元素都是奇数。如果可以实现,则返回 1;否则,返回 0。
例如:给定数组 A = [3, 5, 2],第一次操作中可以删除 A[1],数组变为 [3, 2]。接下来,再删除 A[1],数组变为 [3]。此时,数组中的所有元素都是奇数,因此返回 1。
这是我觉得最最最简单的一个题目了,但是他被归类为中等题目,不是很理解,代码就一行即可,如下:
public static int solution(int n, int[] A) {
return A[0] % 2;
}
题目中给出,删除了一个数后,后面的数字会往前补,所以如果想要保证数组剩下的元素都是奇数,我只需要满足第一个元素是奇数即可,因为即使我出现第偶数序数无法删除的情况,我只需要删除其前一个元素即可。最后只剩下第一个元素,那么第一个元素是奇数就行。
T350. 判断两个不完整数字的大小
小M得到了两个长度为K的整数X和Y,其中某些数字是缺失的(用?表示)。现在他想知道是否可以肯定地说X严格大于Y。如果答案是肯定的,返回1;否则返回0。
请注意,X和Y中都不能有前导0,即任何一方的数字不能以0开头。
代码如下:
public static int solution(int K, String X, String Y) {
for (int i = 0; i < K; i++){
if (Y.charAt(i) == '?') {
if (X.charAt(i) != '9'){
return 0;
}else {
continue;
}
}
if (X.charAt(i) == '?' && Y.charAt(i) != '0') {
return 0;
}else if (X.charAt(i) == '?' && Y.charAt(i) == '0') {
continue;
}
if (Integer.parseInt(String.valueOf(X.charAt(i))) <Integer.parseInt(String.valueOf(Y.charAt(i))) ) {
return 0;
}else if (Integer.parseInt(String.valueOf(X.charAt(i))) >Integer.parseInt(String.valueOf(Y.charAt(i))) ) {
return 1;
}
}
return 0;
}
这道题我的代码中 if 太多了,但是目前还没想好怎么修改。题目中返回 1 的唯一办法就是 X 的某位数的值大于 Y 对应的值。所以如果循环结束了,那么 X 就不会大于 Y,就会返回 0.
首先判断 Y 是不是'?',如果 Y 是'?',那么 X 就必须要是 9,不如就直接返回 0。其次对 X 是'?'的情况讨论,此时 Y 只能是'0',不然就返回 0;最后就是对 X 和 Y 分别拆解了,因为不含'?',只需要对对应的数字进行比较即可。不需要对相等的情况做处理。
T437 数组操作次数计算
小C得到了一个数组,他要对这个数组进行一些操作,直到数组为空。每次操作时,他会执行以下步骤:
- 如果数组的第一个元素 a[0] 等于0,则直接删除 a[0],并将数组中剩余的所有元素向左移动以填补空缺。
- 否则,将 a[0] 个 a[0]-1 添加到数组末尾,并将 a[0] 减少1。
小C想知道,在进行这些操作直到数组为空时,总共进行了多少次操作。结果需要对 10^9 + 7 取模
代码如下:
private static long[] dp = new long[1000];
public static long getValue(int n) {
if (n == 0) {
return 1;
}
if (dp[n] != 0) {
return dp[n];
}else {
dp[n] = getValue(n - 1) * ( n + 1) + 1;
return dp[n];
}
}
public static int solution(int n, int[] a) {
long count = 0;
for (int i : a) {
count += getValue(i);
count %= 1000000007;
}
return (int) count;
}
这题主要就是想清楚其实每个数字会执行的操作次数是固定且与下一个数字相关的,就比如 3,在第一次操作的时候,会将首位变成 2,随后会添加 3 个 2 在数组的末尾,那么接下来就需要进行 4 个 2 的操作。所以对于数字 3,就需要(3+1)*dp[2] + 1 次操作。后面的加一是最开始变成四个 2 的操作。
想清楚这点的话,题目就会变得简单起来了,我们只需要写一个递归函数,f(n) = (n+1) * f(n-1)+1 即可。至于我给出的代码中使用的 dp 数组,是为了存储已经记录过的值,可以避免一些重复的递归。同时也可以降低时间复杂度。