每日算法
2022.4.10
804. 唯一摩尔斯密码词
难度简单224收藏分享切换为英文接收动态反馈
国际摩尔斯密码定义一种标准编码方式,将每个字母对应于一个由一系列点和短线组成的字符串, 比如:
'a'
对应".-"
,'b'
对应"-..."
,'c'
对应"-.-."
,以此类推。
为了方便,所有 26
个英文字母的摩尔斯密码表如下:
[".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."]
给你一个字符串数组 words
,每个单词可以写成每个字母对应摩尔斯密码的组合。
- 例如,
"cab"
可以写成"-.-..--..."
,(即"-.-."
+".-"
+"-..."
字符串的结合)。我们将这样一个连接过程称作 单词翻译 。
对 words
中所有单词进行单词翻译,返回不同 单词翻译 的数量。
示例 1:
输入: words = ["gin", "zen", "gig", "msg"]
输出: 2
解释:
各单词翻译如下:
"gin" -> "--...-."
"zen" -> "--...-."
"gig" -> "--...--."
"msg" -> "--...--."
共有 2 种不同翻译, "--...-." 和 "--...--.".
class Solution {
public int uniqueMorseRepresentations(String[] words) {
//使用hashset进行去重
HashSet<String> ans = new HashSet<String>();
//codes存放编码
String[] codes =new String[]{".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
//用来存放每次译码的结果
String result = "";
for(String a:words){
//每次循环初始化result
result = "";
for(int i=0;i<a.length();i++){
//计算译码的位置
int j = a.charAt(i) - 'a';
result += codes[j];
}
ans.add(result);
}
return ans.size();
}
}
780. 到达终点
难度困难246收藏分享切换为英文接收动态反馈
给定四个整数 sx
, sy
,tx
和 ty
,如果通过一系列的转换可以从起点 (sx, sy)
到达终点 (tx, ty)
,则返回 true
,否则返回 false
。
从点 (x, y)
可以转换到 (x, x+y)
或者 (x+y, y)
。
示例 1:
输入: sx = 1, sy = 1, tx = 3, ty = 5
输出: true
解释:
可以通过以下一系列转换从起点转换到终点:
(1, 1) -> (1, 2)
(1, 2) -> (3, 2)
(3, 2) -> (3, 5)
示例 2:
输入: sx = 1, sy = 1, tx = 2, ty = 2
输出: false
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
//递归解决
if(sx==tx&&sy==ty){
return true;
}
//如何判定失败:一个点只能向前走,如果终点在后面,判定失败。
if(sx<tx||sy<ty){
return false;
}
return reachingPoints(sx+sy,sy,tx,ty) || reachingPoints(sx,sy+sx,tx,ty);
}
结果执行错误因为一些用例数据过大,导致栈溢出。
正解:逆向思维
//从(tx, ty)推到(sx, sy),则时只能有一种操作,就是将tx、ty中较大值减去较小值(因为顺推的时候是(x, y)
//可以转换到 (x, x+y) 或者 (x+y, y)
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
while (tx > 0 && ty > 0){//因为sx, sy, tx, ty 是范围在 [1, 10^9] 的整数,逆推不能出界
if (sx == tx && sy == ty){//判断是否到达了起始值
return true;
}
//每次逆推只能有tx、ty中较大值减去较小值
if (tx > ty){//此时只能有tx减去ty
tx -= ty;
}
else{//此时只能有ty减去tx
ty -= tx;
}
}
return false;
}
妙蛙。
然后:
结果超时,我。。。。。。这。。。
再优化思路:当反向推的时候,路径是唯一的。
回顾一下gcd的算法:辗转相除法与更相减损术。贴一个链接:https://blog.csdn.net/THISISPAN/article/details/7458234
所以:
更相减损法到辗转相除法的进化。如果遇到一个数很大,另一个数比较小的情况,可能要进行很多次减法才能达到一次除法的效果,从而使得算法的时间复杂度退化为O(N),其中N是原先的两个数中较大的一个
class Solution {
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
//变相gcd
if (tx < sx || ty < sy) return false;
if (tx > ty) {
//此时tx不可能==sx,如果sy==ty,就判断tx是不是有可能转成sx
if (sy == ty)
return sx >= (tx % ty) && (tx - sx) % sy == 0;
return reachingPoints(sx, sy, tx % ty, ty);
}else if (tx < ty){
if (sx == tx)
return sy >= (ty % tx) && (ty - sy) % sx == 0;
return reachingPoints(sx, sy, tx, ty % tx);
}else return tx == sx && ty == sy;
}
}
贴一个gcd
public int gcd(int a,int b){
int big = a>b?a:b;
int small = a<b?a:b;
if(big%small==0){
return small;
}
return gcd(small,big%small);
}