文章目录
- (易)计算从位置x到y的最少步数
- (易)环状DNA序列的最小表示法
- (易)打点计时器的区间合并
- (易)分组飞行器棋子
- (易)数列差异的最小化(半成品)
- (易)完美整数
- (易)版本号比较
- (易)找出整型数组中占比超过一半的数
- (易)寻找单独数组卡片
- (易)寻找最大葫芦
- (易)小D的`abc`变换问题
- (中)数字魔法的加一操作
- (中)最优硬币组合问题
- (中)有限制的楼梯攀登
- (中)摇骰子的胜利概率
- (中)和的逆运算问题(半成品)
- (难)二进制之和
(易)计算从位置x到y的最少步数
问题描述
小F正在进行一个 AB 实验,需要从整数位置x
移动到整数位置y
。每一步可以将当前位置增加或减少,且每步的增加或减少的值必须是连续的整数(即每步的移动范围是上一步的-1
,+0
或+1
)。首末两步的步长必须是1
。求从x
到y
的最少步数。
输入描述
输入包含两个整数x
和y
,表示起始位置和目标位置。
输出描述
输出从x
到y
所需的最小步数。
测试样例
样例1:
输入: x p o s i t i o n = 12 , y p o s i t i o n = 6 x_position = 12, y_position = 6 xposition=12,yposition=6
输出:4
样例2:
输入: x p o s i t i o n = 34 , y p o s i t i o n = 45 x_position = 34, y_position = 45 xposition=34,yposition=45
输出:6
样例3:
输入: x p o s i t i o n = 50 , y p o s i t i o n = 30 x_position = 50, y_position = 30 xposition=50,yposition=30
输出:8
样例4:
输入: x p o s i t i o n = 0 , y p o s i t i o n = 0 x_position = 0, y_position = 0 xposition=0,yposition=0
输出:0
解题思路
这个思路似乎不太一样,我们来看,题目有两个关键要求:一个是步数最少,一个是相邻两步之间只能是+1,-1,+0三种情况。
那我们以 1 、 2 、 3 、 4 、 3 、 2 、 1 1、2、3、4、3、2、1 1、2、3、4、3、2、1为例,此时的距离是16;而 1 、 2 、 3 、 4 、 5 、 4 、 3 、 2 、 1 1、2、3、4、5、4、3、2、1 1、2、3、4、5、4、3、2、1时,此时的距离是25;先得出一个小规律,这样的分布总距离是 n ∗ n n*n n∗n(n是最中间的那个数)。
然后呢,我们假设目标距离是20,那是不是只要在第一个数列中间添加一个4,也就是: 1 、 2 、 3 、 4 、 4 、 3 、 2 、 1 1、2、3、4、4、3、2、1 1、2、3、4、4、3、2、1,那么最少步数就是8。
那20和25之间还有一段距离,如果目标距离在这一段呢,我们可以在第三个数列的基础上继续添加,那就有疑问了:为什么不是第二个呢?这就涉及到第二个限制条件:相邻两步之间只能是+1,-1,+0,当你的这一组数列中出现5时,5的左右两侧至少各有1个4,符合限制的最短距离和就是25,超出了。所以呢,假设目标距离是23,那么也就是在第三个数组的基础上再插入一个3,也就是: 1 、 2 、 3 、 4 、 4 、 3 、 3 、 2 、 1 1、2、3、4、4、3、3、2、1 1、2、3、4、4、3、3、2、1此时的最少步数是9。
此外,还有一种特殊情况:如果两个位置之间的距离是0,那么我们原本思路的对n进行微操似乎就不太合适,那我们就在方法最开始的位置填上一个判断条件,如果距离是0,那么直接返回0即可。
public class Main {
public static int solution(int xPosition, int yPosition) {
int len = Math.abs(yPosition-xPosition);
if(len==0){
return 0;
}
int n=0;
do {
n++;
}while(n*n<=len);
n--;
if(len-n*n==0){
return n+n-1;
}else if(len-n*n<=n){
return n*2;
}else{
return n*2+1;
}
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution(12, 18) == 4);
System.out.println(solution(34, 45) == 6);
System.out.println(solution(50, 30) == 8);
System.out.println(solution(50, 27) == 9);
System.out.println(solution(50, 35) == 7);
}
}
(易)环状DNA序列的最小表示法
问题描述
小C正在研究一种环状的 DNA 结构,它由四种碱基A、C、G、T构成。这种环状结构的特点是可以从任何位置开始读取序列,因此一个长度为 n 的碱基序列可以有 n 种不同的表示方式。小C的任务是从这些表示中找到字典序最小的序列,即该序列的“最小表示”。
例如:碱基序列 ATCA 从不同位置读取可能的表示有 ATCA, TCAA, CAAT, AATC,其中 AATC 是字典序最小的表示。
测试样例
样例1:
输入:dna_sequence = “ATCA”
输出:‘AATC’
样例2:
输入:dna_sequence = “CGAGTC”
输出:‘AGTCCG’
样例3:
输入:dna_sequence = “TTGAC”
输出:‘ACTTG’
解题思路:
什么是字典序呢?简单来说,就是一个字符的 A S C L L 码 ASCLL码 ASCLL码。
这道题的意思就是给你一个字符串,以字符串的不同位置作为开头,诶个比较不同字符串中的字符,直到返回字典序最小的那个字符串。以ATCA
为例,它的可能序列一共有4
种: A T C A ATCA ATCA T C A A TCAA TCAA C A A T CAAT CAAT A A T C AATC AATC那么解题流程也就是比较四组字符串各自的第一个字符,得到 A T C A ATCA ATCA A A T C AATC AATC比较这两组的第二个字符,得到字典序最小的: A A T C AATC AATC
但是呢,我们将思路用在计算机上,发现如果可能序列足够多的话,这样比较起来会非常冗杂,所以我们需要一个更简洁的思路:那么我们是不是可以尝试两个两个比较,字典序较小的与下一个字符串进行比较,然后再返回较小的,接着进行比较,当我们把所有字符开头的序列都比较过之后,就得到了最终的最小序列。
但是呢,稍微想一想,似乎这里也有一种特殊情况:如果字符串中的所有字符都是同一种字母组成的呢,此时我们原本的比较方法 c o m p a r e compare compare似乎就不太行了,那这一种我们也可以单拉出来作为一种情况讨论,如果测试字符串仅由一种字母构成,那我们直接返回原字符串。
import java.util.Arrays;
public class Main {
public static String solution(String dna_sequence) {
if(allSame(dna_sequence)){
return dna_sequence;
}
int len = dna_sequence.length();
String min_str = dna_sequence;
for (int i = 1; i < len; i++) {
// System.out.println(dna_sequence.substring(i)+dna_sequence.substring(0, i));
min_str = compare(min_str, dna_sequence.substring(i)+dna_sequence.substring(0, i));
}
return min_str;
}
// 传入俩个等长的字符串,诶个字母比较谁的字典序更小,传出较小的那一位
public static String compare(String str1, String str2) {
for(int i=0;i<str1.length();i++){
if(str1.charAt(i) < str2.charAt(i)){
return str1;
}else if(str1.charAt(i) > str2.charAt(i)){
return str2;
}else{
continue;
}
}
return "";
}
public static boolean allSame(String str){
//判断该字符串中的所有字母都只是同一种字母
for(int i=0;i<str.length()-1;i++){
if(str.charAt(i) != str.charAt(i+1)){
return false;
}
}
return true;
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution("ATCA").equals("AATC"));
System.out.println(solution("CGAGTC").equals("AGTCCG"));
System.out.println(solution("TCATGGAGTGCTCCTGGAGGCTGAGTCCATCTCCAGTAG").equals("AGGCTGAGTCCATCTCCAGTAGTCATGGAGTGCTCCTGG"));
}
}
(易)打点计时器的区间合并
问题描述
小明想发明一台打点计数器,这个计数器有这样的一个功能:
- 它可以接收一个递增的数据范围(形如[3, 9]),其中第一个数字代表起始,第二个数字代表结束
- 这个数据范围中包含几个数字,打点计数器就会打几个点
- 在传入的多组数据范围中,如果出现了范围的重复,机器则不会重复打点
你可以帮助小明算一算,在不同的情况下,计数器会打出几个点么?
输入格式
一个二维数组
输出格式
一个整数,表达在输入是这个数组的情况下,计数器打出的点数
输入样例(1)
[ [1,4], [7, 10], [3, 5] ]
输出样例(1)
7
输入样例(2)
[ [1,2], [6, 10], [11, 15] ]
输出样例(2)
9
数据范围
- 数 字 范 围 [ − 1 0 9 , 1 0 9 ] 数字范围[-10^9, 10^9] 数字范围[−109,109],$数组长度 < 2^{16} $
解题思路
这个就很简单啦,我们遍历每个区间,将出现的元素全部存入集合中(集合中元素不会重复),然后再统计元素的个数即可求解。
import java.util.Set;
import java.util.HashSet;
public class Main {
public static int solution(int[][] inputArray) {
// Please write your code here
Set<Integer> set = new HashSet<>();
for(int i=0;i<inputArray.length;i++){
for(int j=inputArray[i][0];j<inputArray[i][1];j++){
set.add(j);
}
}
return set.size();
}
public static void main(String[] args) {
// You can add more test cases here
int[][] testArray1 = {
{
1, 4}, {
7, 10}, {
3, 5}};
int[][] testArray2 = {
{
1, 2}, {
6, 10}, {
11, 15}};
System.out.println(solution(testArray1) == 7);
System.out.println(solution(testArray2) == 9);
}
}
(易)分组飞行器棋子
问题描述
小M和小F在玩飞行棋。游戏结束后,他们需要将桌上的飞行棋棋子分组整理好。现在有 N 个棋子,每个棋子上有一个数字序号。小M的目标是将这些棋子分成 M 组,每组恰好5个,并且组内棋子的序号相同。小M希望知道是否可以按照这种方式对棋子进行分组。
例如,假设棋子序号为 [1, 2, 3, 4, 5],虽然只有5个棋子,但由于序号不同,因此不能形成有效的分组。如果序号是 [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],则可以形成两个有效分组,因此输出为 True。
测试样例
样例1:
输入:nums = [1, 2, 3, 4, 5]
输出:“False”
样例2:
输入:nums = [1, 1, 1, 1, 2, 1, 2, 2, 2, 2]
输出:“True”
样例3:
输入:nums = [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
输出:“True”
样例4:
输入:nums = [7, 7, 7, 8, 8, 8, 8, 8, 7, 7]
输出:“True”
样例5:
输入:nums = [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
输出:“False”
解题思路
import java.util.Map;
import java.util.HashMap;
public class Main {
public static String solution(int[] nums) {
Map<Integer, Integer> countNum = new HashMap<>();
for (int num : nums) {
countNum.put(num, countNum.getOrDefault(num, 0) + 1);
}
for (Map.Entry<Integer, Integer> entry : countNum.entrySet()) {
if (entry.getValue()%5==0) {
continue;
} else {
return "False";
}
}
return "True";
}
public static void main(String[] args) {
System.out.println(solution(new int[]{
1, 3, 4, 5, 6, 5, 4}).equals("false"));
System.out.println(solution(new int[]{
1, 1, 1, 1, 2, 1, 2, 2, 2, 2}).equals("true"));
System.out.println(solution(new int[]{
11, 45, 49, 37, 45, 38, 3, 47, 35, 49, 26, 16, 24, 4, 45, 39, 28, 26, 14, 22, 4, 49, 18, 4, 4, 26, 47, 14, 1, 21, 9, 26, 17, 12, 44, 28, 24, 24, 10, 31, 33, 32, 23, 41, 41, 19, 17, 24, 28, 46, 28, 4, 18, 23, 48, 45, 7, 21, 12, 40, 2, 19, 19, 28, 32, 6, 27, 43, 6, 18, 8, 27, 9, 6, 6, 31, 37, 15, 26, 20, 43, 3, 14, 40, 20}).equals("false"));
}
}
(易)数列差异的最小化(半成品)
问题描述
给定长度分别为 n
和 m
的两个数列a[n]
、b[m]
,和一个整数k
。求 ∣ ( a [ i ] − b [ j ] ) 2 − k 2 ∣ |(a[i] - b[j])^2 - k^2| ∣(a[i]−b[j])2−k2∣的最小值。
输入格式
第一行有 2 个整数 n
、m
、k
,分别表示数列 a
、b
的长度,以及公式中的整数 k
。
第二行有 n
个整数,表示数列 a
的各个元素。
第三行有 m
个整数,表示数列 b
的各个元素。
输出格式
求上述公式的最小值。
数据范围
其中 20%的数据: 1 < = n , m < = 3000 , − 1 0 9 < = a [ i ] , b [ j ] , k < = 1 0 9 , f o r a l l i , j 1 <= n,m <= 3000,-10^9 <= a[i], b[j], k <= 10^9,for all i, j 1<=n,m<=3000,−109<=a[i],b[j],k<=109,foralli,j
其中 30%的数据: 1 < = n , m < = 50000 , k = 0 , − 1 0 9 < = a [ i ] , b [ j ] < = 1 0 9 , f o r a l l i , j 1 <= n,m <= 50000,k = 0,-10^9 <= a[i], b[j] <= 10^9,for all i, j 1<=n,m<=50000,k=0,−109<=a[i],b[j]<=109,foralli,j
其中 50%的数据: 1 < = n , m < = 50000 , − 1 0 9 < = a [ i ] , b [ j ] , k < = 1 0 9 , f o r a l l i , j 1 <= n,m <= 50000,-10^9 <= a[i], b[j], k <= 10^9,for all i, j 1<=n,m<=50000,−109<=a[i],b[j],k<=109,foralli,j
输入样例
5 5 1
5 3 4 1 2
0 6 7 9 8
5 5 0
5 3 4 1 2
0 6 7 9 8
输出样例
0
1
解题思路
import java.util.List;
public class Main {
public static int solution(int n, int m, int k, List<Integer> a, List<Integer> b) {
int min = Integer.MAX_VALUE;
for (int i = 0; i < a.size(); i++) {
for (int j = 0; j < b.size(); j++) {
int temp = sum(a.get(i), b.get(j), k);
if (temp < min) {
min = temp;
}
}
}
return min;
}
public static int sum(int a, int b, int c) {
return Math.abs((a - b) * (a - b) - c * c);
}
public static void main(String[] args) {
int n = 16;
int m = 11;
int k = 25;
List<Integer> a = List.of(5, 11, 4, 24, 3, 14, 16, 22, 4, 3, 5, 12, 12, 11, 12, 18);
List<Integer> b = List.of(23, 16, 6, 20, 1, 10, 16, 17, 17, 1, 23);
System.out.println(solution(n, m, k, a, b));
}
}
(易)完美整数
问题描述
一个整数如果由相同的数字构成,则称为完美整数。例如:
1、11、333
是完美整数。12、19、101
是不完美整数。
现在,你需要计算给定区间 [x, y] 中有多少个整数是完美整数。
测试样例
样例1:
输入:x = 1 ,y = 10
输出:9
样例2:
输入:x = 2 ,y = 22
输出:10
解题思路
public class Main {
public static int solution(int x, int y) {
int count = 0;
for (int i = x; i <= y; i++) {
if (perfectNum(i)) {
count++;
}
}
return count;
}
public static boolean perfectNum(int x) {
if (x >= 1 && x <= 9) {
return true;
} else if (x >= 10) {
int lastNum = x % 10;
x = x / 10;
while (x > 0) {
int temp = x % 10;
if (temp == lastNum) {
x = x / 10;
} else {
return false;
}
}
return true;
} else {
return false;
}
}
public static void main(String[] args) {
System.out.println(solution(1, 10) == 9);
System.out.println(solution(2, 22) == 10);
}
}
(易)版本号比较
问题描述
在某个项目中,每个版本都用版本号标记,由一个或多个修订号组成,修订号之间由点号.分隔。每个修订号可能有多位数字,并且可能会包含前导零。你需要根据两个版本号version1
和version2
,判断哪个版本更新,或者它们是否相同。
例如,2.5.33
和0.1
都是有效的版本号。
当比较两个版本时,从左到右依次比较它们的修订号。忽略每个修订号的前导零,直接比较修订号对应的整数值。如果其中一个版本没有足够的修订号,缺失部分默认补为0
。
你需要根据以下规则返回比较结果:
- 如果
version1 > version2
,返回1
。 - 如果
version1 < version2
,返回-1
。 - 如果两个版本相等,返回
0
。
测试样例
样例1:
输入:version1 = “0.1” , version2 = “1.1”
输出:-1
样例2:
输入:version1 = “1.0.1” , version2 = “1”
输出:1
样例3:
输入:version1 = “7.5.2.4” , version2 = “7.5.3”
输出:-1
样例4:
输入:version1 = “1.0” , version2 = “1.0.0”
输出:0
解题思路
public class Main {
public static void main(String[] args) {
System.out.println(solution("0.1", "1.1") == -1);
System.out.println(solution("1.0.1", "1") == 1);
System.out.println(solution("7.5.2.4", "7.5.3") == -1);
System.out.println(solution("1.0", "1.0.0") == 0);
}
public static int solution(String version1, String version2) {
// Edit your code here
String[] v1=version1.split("\\.");
String[] v2=version2.split("\\.");
StringBuilder v11=new StringBuilder();
StringBuilder v22=new StringBuilder();
for(String part:v1){
v11.append(part);
}
for(String part:v2){
v22.append(part);
}
while(v11.length()>v22.length()){
v22.append("0");
}
while(v11.length()<v22.length()){
v11.append("0");
}
int v111=Integer.parseInt(v11.toString());
int v222=Integer.parseInt(v22.toString());
if(v111>v222){
return 1;
}else if(v111<v222){
return -1;
}else {
return 0;
}
}
}
(易)找出整型数组中占比超过一半的数
问题描述
小R从班级中抽取了一些同学,每位同学都会给出一个数字。已知在这些数字中,某个数字的出现次数超过了数字总数的一半。现在需要你帮助小R找到这个数字。
测试样例
样例1:
输入:array = [1, 3, 8, 2, 3, 1, 3, 3, 3]
输出:3
样例2:
输入:array = [5, 5, 5, 1, 2, 5, 5]
输出:5
样例3:
输入:array = [9, 9, 9, 9, 8, 9, 8, 8]
输出:9
解题思路
import java.util.Map;
import java.util.HashMap;
public class Main