演练:字符串中的反转元音
演练:字符串中的反转元音
朋友们好,这是 Saadin 告诉你我如何解决 LeetCode 中的一个问题。让我们直接潜入。废话,我们走吧。
问题
给定一个字符串
s
,仅反转字符串中的所有元音并返回它。元音是
'一个'
,'e'
,'一世'
,'o'
, 和“你”
,并且它们可以出现在这两种情况下。
在这个例子中,如果我把单词“hello”作为我的字符串,我的方法必须返回字符串“holle”。
忘记 1 和 0
好的,所以首先,让我们暂时放下电脑谈话。我从 Gayle Laakmann McDowell 的 破解编码面试。 如果我告诉一个中学生实施二分搜索,他们要么当场放弃,要么他们的小脑袋可能会爆炸,除非我在和我说话 马尔科姆·威尔克森 .
但是,如果我告诉他们拿一本字典并在其中找到“quest”这个词,你可以很确定他们会做类似二进制搜索的事情:他们会知道“q”比“z”更接近它是'a',所以他们会走到书的结尾。也许那时他们会按“v”,所以他们会开始翻页。然后他们会向后翻转并按“p”。又太远了。最后,他们会按“q”并找到 quest 这个词。
上述过程是合乎逻辑的,其概念类似于二分查找。不要迷失在我们正在制作算法的事实中。想想现实世界的解决方案是什么。我可能仍然会使用蛮力,但我的蛮力会稍微聪明一些。
就我而言,我只想翻转元音,所以我将左右食指指向弦的两端;一个在索引 0 处,然后一个在索引 n-1 处,其中 n 是字符串中的字符数。
我想把我的手指越来越近,一个字母一个字母地走。如果我用一根手指敲击元音,我会停下来;当我在另一根手指上敲击元音时,我翻转它们,然后继续我的过程。
酷,让我们把这个概念带到计算机上。
蛮力
诚然,我以前没有见过这个问题,所以我会尝试实施我的解决方案,这可能会变得混乱。但它会做。
首先,我们将字符串转换成一个字符数组,称为 单词
因为字符串是不可变的,因此使用起来有点烦人。
然后我们用两个变量设置了一个while循环。一个会去 s.length()-1
- AKA 最后一个索引 - 另一个将从索引 0 开始。循环结束时 一世
大于 j
.这是我最初提出的完整解决方案:
公共字符串反向元音(字符串 s){
char[] word = new char[s.length()];
for (int i = 0; i < s.length(); i++) {
字[i] = s.charAt(i);
}
诠释 i = 0;
int j = s.length() - 1;
堆<Integer>iq = 新堆栈<Integer>();
堆<Integer>jq = 新堆栈<Integer>();
而 (i < j) {
if (/*检查 word[i] 是否为元音*/) {
iq.add(i);
}
if (/*检查 word[j] 是否是元音*/) {
jq.add(j);
}
if (!iq.isEmpty() && !jq.isEmpty()) {
//我们找到了必须交换的两个元音!翻转它们!
iq.pop();
char tempC = word[i];
jq.pop();
词[i] = 词[j];
词[j] = tempC;
}
if (iq.isEmpty()) i++;
if (jq.isEmpty()) j--;
}
返回新字符串(单词);
}
起初,我以为我会继续迭代,然后记下索引,以便在变量不断迭代的同时进行交换。这没有帮助,但我并没有摆脱堆栈的想法。我保留它以检查我的变量是否必须迭代(稍后会详细介绍)。
当我迭代时,我检查是否 词[j]
或者 词[我]
其中有元音。如果他们这样做,我将索引压入堆栈。
两个堆栈都有东西吗?太好了,我们交换了 一世
和 j
.如果变量对应的栈为空,则迭代。如果没有,不要。
磨练算法
好吧,是时候问什么会更好了。
什么工作被做了两次?不管你多么聪明,你都会犯错,所以问自己这些问题很重要。我认为我通常很擅长解决算法问题,但我肯定注意到我的代码有些地方不太好。
我的筹码只有一个值;最重要的是,它们的一个值始终等于它们对应的值 一世
或者 j
多变的。我正在存储我不需要的信息。所以我用一种原始的、更轻的数据类型替换了堆栈:布尔值。我做一个 移动
__ 和 移动
__ 变量,我将这两个都设置为true。如果我的性格在 j
或者 一世
是元音,我将相应的布尔值设为假。如果 移动
是真的,我们迭代 一世 .如果 移动
是真的,我们迭代 j
.这将使我的算法的空间复杂度好一点。这是完整的解决方案:
类解决方案{
公共字符串反向元音(字符串 s){
char[] word = new char[s.length()];
for (int i = 0; i < s.length(); i++) {
字[i] = s.charAt(i);
}
诠释 i = 0;
int j = s.length() - 1;
布尔 iMove = true;
布尔 jMove = true;
堆<Integer>jq = 新堆栈<Integer>();
而 (i < j) {
if (/*检查 word[i] 是否为元音*/) {
iMove = 假;
}
if (/*检查 word[j] 是否是元音*/) {
jMove = 假;
}
如果 (!iMove && !jMove) {
//我们找到了必须交换的两个元音!翻转它们!
char tempC = word[i];
词[i] = 词[j];
词[j] = tempC;
iMove =真;
jMove =真;
}
如果 (iMove) i++;
如果 (jMove) j--;
}
返回新字符串(单词);
}
}
最坏的输入场景是一串字符,最后只有两个元音。该算法将运行 n-2 个条目,因此我们的大 O 时间是 O(n-2),可以简化为 O(n)。
包起来
你怎么知道你已经完成了,没有办法变得更好?好吧,让我们想想我们在做什么。
我们缺乏关于元音在哪里或字符串包含多少元音的信息,所以我们绝对必须找出每个字符是什么,这意味着我们必须遍历 n 个字符。即使在理论上,我们最好的情况下运行时间也是 O(n)。我的算法是 O(n),所以我们开始了!如果不是当然,那意味着我可以以某种方式做得更好。幸运的是,这对我来说不是这样。
祝大家编码愉快!
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明