题目背景
小明正在玩一个"翻硬币"的游戏。
题目描述
桌上放着排成一排的若干硬币。我们用 *
表示正面,用 o
表示反面(是小写字母,不是零),比如可能情形是 **oo***oooo
,如果同时翻转左边的两个硬币,则变为 oooo***oooo
。现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
输入格式
两行等长字符串,分别表示初始状态和要达到的目标状态,每行长度小于 10001000。
数据保证一定存在至少一种方案可以从初始状态和要达到的目标状态。
输出格式
一个整数,表示最小操作步数。
输入输出样例
输入 #1复制
**********
o****o****
输出 #1复制
5
输入 #2复制
*o**o***o***
*o***o**o***
输出 #2复制
1
需要明确的一个事实就是只用按顺序遍历,并且左右都一样(只和最远的两个不同点所在的区间有关)。
java
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
String x,y;
int num = 0;
char a[] = new char[1000];
char b[] = new char[1000];
try (Scanner sc = new Scanner(System.in)) {
x = sc.nextLine();
y = sc.nextLine();
}
for(int i =0; i<x.length();i++) {
a[i] = x.charAt(i);
b[i] = y.charAt(i);
}
for(int i =0; i<x.length();i++) {
if(a[i] == b[i]) {
continue;
}else {
a[i+1] =(a[i+1]=='*' ?'o':'*') ;
num++;
}
}
System.out.println(num);
}
}
在这个代码里面
java
a[i+1] =(a[i+1]=='*' ?'o':'*') ;
整一个被依据条件赋予了'o'或者'?'。并且要比下面这个情况(我写的)好多了:
java
package 练习; import java.util.; public class 第一次
{ public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
StringBuilder str1 = new StringBuilder();
StringBuilder str2 = new StringBuilder();
int m; for(int i = 1 ; i <= 1000; i++) {
if(str1.charAt(i) != str2.charAt(i)) {
if(str1.charAt(i) = '') str1.insert(i,'o');
else
str1.insert(i,'*');
if(i < 1000 && str1.charAt(i + 1) == '*')
str1.insert(i,'o');
else
str1.insert(i,'*');
m++;
i++;
}
}
}
}
一句顶我好几句。
由此可见这种根据条件选择的非此即彼的判断选择要用a > b ? x:y;这样的三元语句。
看了别人的解法:
-
由于不会有无解的情况,我们可以从左至右依次循环遍历 字符串的每一个字符,判断是不是与 串相应的字符相等。
-
若不相等,翻转这枚和下一枚(他右边的)硬币。
-
这里可以偷个懒,由于之后不会再用到这枚硬币,可以不翻,只翻下一枚。
cpp#include<bits/stdc++.h> using namespace std; char a[1005]; char b[1005]; int main(){ cin>>a>>b; int len=strlen(a); int i=0,sum=0; while(i<len){ if(a[i]!=b[i]){ a[i+1]=(a[i+1]=='*'?'o':'*'); sum++; } i++; } cout<<sum; return 0; }
这样计算的量级减少了几个N(不看大的O(N),看具体的细节)
还有一种方法,虽然没有优化但是可以看看不同的角度下的人是如何理解这一个题目的:
cpp
#include<bits/stdc++.h>
using namespace std;
string a, b;
int ans, bg = -1, n;
int main(){
cin >> a >> b;
n = a.length();
for(int i = 0; i < n; i++){
if(a[i] != b[i]){
if(bg == -1){//找第一个不同的硬币
bg = i;
}else{
ans += (i - bg);//找到第二个不同的硬币
bg = -1;//接着找下一个不同段
}
}
}
cout << ans;
return 0;
}
这里其实就是运用了基本结构构建思想(就是欧拉解决戈尼斯堡七座桥难题的那个思想)**对oo、
*******对o*******o 、*****对o***o 、n 个*对o(这里n个'*')o结构其实都一样,而所有的硬币排序都可以被拆成这这样的结构,而这样的结构翻成对应的状态所需要的次数有规律(整个小结构字符数量减去1就是翻转次数),所以可以。