1.找出最长的神奇数列
- 问题描述
- 小F是一个好学的中学生,今天他学习了数列的概念。他在纸上写下了一个由 0 和 1 组成的正整数序列,长度为 n。这个序列中的 1 和 0 交替出现,且至少由 3 个连续的 0 和 1 组成的部分数列称为「神奇数列」。例如,10101 是一个神奇数列,而 1011 不是。现在,小F想知道在这个序列中,最长的「神奇数列」是哪一个。你能帮他找到吗? 如果有多个神奇数列,那么输出最先出现的一个。!
- 思路
-
检查初始条件:
-
if (inp[i] != inp[i + 1] && inp[i + 1] != inp[i + 2]):
- 检查当前位置 i、i + 1 和 i + 2 是否满足 0 和 1 交替出现的条件。
- 如果满足条件,说明从 i 开始的子序列可能是神奇数列。
-
-
扩展子序列:
-
int j = i + 2;:
- 初始化 j 为 i + 2,表示从 i + 2 开始继续检查。
-
while (j < len && inp[j] != inp[j - 1]):
- 循环检查 inp[j] 和 inp[j - 1] 是否不相等(即 0 和 1 交替出现)。
- 如果相等,说明交替结束,退出循环。
- ++j;:每次循环 j 增加 1,继续检查下一个字符。
-
-
计算当前子序列长度:
-
int current_length = j - i;:
- 计算从 i 到 j 的子序列长度。
-
-
更新最长子序列:
-
if (current_length > max_length):
- 如果当前子序列长度 current_length 大于 max_length,则更新 max_length 和 max。
-
max_length = current_length;:
- 更新 max_length 为当前子序列长度。
-
max = inp.substr(i, current_length);:
- 更新 max 为当前子序列。
-
-
跳过已经检查过的部分:
- i = j - 2; 将 i 设置为 j - 2,跳过已经检查过的部分,避免重复检查。
- 代码
#include<iostream>
#include <string>
std::string solution(const std::string &inp) {
int len = inp.size();
if (len < 6) return "";
else {
std::string max = "";
int max_length = 0;
for (int i = 0; i < len - 2; i++) {
// 检查从 i 开始的子序列是否是神奇数列
if (inp[i] != inp[i + 1] && inp[i + 1] != inp[i + 2]) {
int j = i + 2;
while (j < len && inp[j] != inp[j - 1]) {
++j;
}
int current_length = j - i;
if (current_length > max_length ) {
max_length = current_length;
max = inp.substr(i, current_length);
}
i = j - 2; // 跳过已经检查过的部分
}
}
return max;
}
}
int main() {
// Add your test cases here
std::cout << (solution("0101011101") == "010101") << std::endl;
return 0;
}
* 2.DNA序列编辑距离
* 问题描述
- 小R正在研究DNA序列,他需要一个函数来计算将一个受损DNA序列(dna1)转换成一个未受损序列(dna2)所需的最少编辑步骤。编辑步骤包括:增加一个碱基、删除一个碱基或替换一个碱基。
* 思路:
-
采用动态规划,使用二维数组dp[][]。第一列表示dna1转化成dna2需要的步数,第二列表示dna2转化成dna1需要的步数。l1、l2分别为dna1、dna2的长度。
-
1.初始化:假设dna1为空,那么dna1转化成dna2需要插入dha2的所有字符,dp[0][j]=j;假设dna2为空,那么dna1转化成dna2需要删除所有字符,即dp[i][0]=i。
-
2.状态转移:如果 dna1[i-1] == dna2[j-1],那么 dp[i][j] = dp[i-1][j-1],因为不需要任何编辑步骤。
-
否则,dp[i][j] 可以通过以下三种方式得到:
- 插入:dp[i][j-1] + 1
- 删除:dp[i-1][j] + 1
- 替换:dp[i-1][j-1] + 1
-
取这三种方式的最小值作为 dp[i][j]。
public class Main { * public static int solution(String dna1, String dna2) { * // Please write your code here * int l1=dna1.length(),l2=dna2.length(); * int \[]\[]dp=new int\[l1+1]\[l2+1]; * for(int i=0;i<=l1;i++){ * dp\[i]\[0]=i; * } * for(int j=0;j<=l2;j++){ * dp\[0]\[j]=j; * } * for(int i=1;i<=l1;i++){ * for(int j=1;j<=l2;j++){ * if(dna1.charAt(i-1)==dna2.charAt(j-1)) * dp\[i]\[j]=dp\[i-1]\[j-1]; * else{ * dp\[i]\[j]=Math.min(dp\[i-1]\[j-1],Math.min(dp\[i-1]\[j],dp\[i]\[j-1]))+1; * } * } * } * return dp\[l1]\[l2]; * } * public static void main(String\[] args) { * // You can add more test cases here * System.out.println(solution("AGCTTAGC", "AGCTAGCT") == 2); * System.out.println(solution("AGCCGAGC", "GCTAGCT") == 4); * } * }
3.小M的弹子游戏机挑战
问题描述
-
小M最近迷上了一款弹子游戏机,规则如下:
-
玩家可以在版面最上方任意一个位置放置弹珠。弹珠会通过得分点时为玩家赢得分数,目标是获得尽可能高的分数。
-
弹子游戏机的版面由两种组成要素构成:
-
钉子(用 -1 表示),当弹珠碰到钉子时,有可能弹射到左下或者右下的位置。
-
得分点(非负整数),弹珠经过得分点时可以获得对应的分数。
-
如果弹珠所在的格子为空(即没有钉子或者得分点),弹珠会直接往下落。
-
小M想知道,在一个给定的版面布局中,他能够获得的最高分数是多少。
-
n 表示版面的高度。
-
m 表示版面的宽度。
-
array 是一个 n x m 的二维数组,其中:
-
-1 表示该位置为钉子;
-
0 表示该位置为空;
-
正整数表示该位置为得分点,值为该得分点的分数。
public class Main {
* public static int solution(int n, int m, int\[]\[] array) {
* // 定义一个二维数组来标记是否访问过某个位置
* boolean\[]\[] visited = new boolean\[n]\[m];
* int maxScore = 0;
* // 遍历起始位置
* for (int i = 0; i < m; i++) {
* maxScore = Math.max(maxScore, dfs(i, 0, 0, array, visited));
* }
* return maxScore;
* }
* public static int dfs(int x, int y, int score, int\[]\[] array, boolean\[]\[] visited) {
* // 检查是否越界
* if (x < 0 || x >= array\[0].length || y >= array.length) {
* return score;
* }
* // 标记当前位置已访问
* visited\[y]\[x] = true;
* // 根据当前位置的情况进行处理
* if (array\[y]\[x] == -1) { // 是钉子
* // 尝试向左下和右下移动
* int scoreLeft = dfs(x - 1, y + 1, score, array, visited);
* int scoreRight = dfs(x + 1, y + 1, score, array, visited);
* visited\[y]\[x] = false; // 回溯,取消访问标记
* return Math.max(scoreLeft, scoreRight);
* } else if (array\[y]\[x] > 0) { // 是得分点
* score += array\[y]\[x];
* }
* // 继续向下移动
* int scoreDown = dfs(x, y + 1, score, array, visited);
* visited\[y]\[x] = false; // 回溯,取消访问标记
* return scoreDown;
* }
* public static void main(String\[] args) {
* // Add your test cases here
* System.out.println(solution(3, 3, new int\[]\[] { { -1, 0, -1 }, { 100, 0, 0 }, { 0, 50, 70 } }) == 50);
* System.out.println(
* solution(4, 3, new int\[]\[] { { -1, 0, -1 }, { 0, -1, 0 }, { 50, 100, 70 }, { 80, 200, 50 } }) == 130);
* }
* }
4.游戏排名第三大的分数
* 问题描述
-
小M想要通过查看往届游戏比赛的排名来确定自己比赛的目标分数。他希望找到往届比赛中排名第三的分数,作为自己的目标。具体规则如下:
-
如果分数中有三个或以上不同的分数,返回其中第三大的分数。
-
如果不同的分数只有两个或更少,那么小M将选择最大的分数作为他的目标。
-
请你帮小M根据给定的分数数组计算目标分数。
* \#include <iostream>
* \#include <set>
* \#include <vector>
* using namespace std;
* int solution(int n, std::vector<int> nums) {
* // write code here
* set<int> a;
* int res;
* for (int i = 0; i < n; i++) {
* a.insert(nums\[i]);
* }
* if (a.size() >= 3) {
* // 反向遍历set,找到第三大的元素
* auto it = a.rbegin();
* it++; // 第二大的元素
* it++; // 第三大的元素
* return \*it;
* } else {
* // 如果不同的分数只有两个或更少,返回最大的分数
* return \*a.rbegin();
* }
* }
* int main() {
* std::cout << (solution(3, {3, 2, 1}) == 1) << std::endl;
* std::cout << (solution(2, {1, 2}) == 2) << std::endl;
* std::cout << (solution(4, {2, 2, 3, 1}) == 1) << std::endl;
* return 0;
* }