演练:字符串中的反转元音

演练:字符串中的反转元音

朋友们好,这是 Saadin 告诉你我如何解决 LeetCode 中的一个问题。让我们直接潜入。废话,我们走吧。

问题

给定一个字符串 s ,仅反转字符串中的所有元音并返回它。

元音是 '一个' , 'e' , '一世' , 'o' , 和 “你” ,并且它们可以出现在这两种情况下。

在这个例子中,如果我把单词“hello”作为我的字符串,我的方法必须返回字符串“holle”。

忘记 1 和 0

Photo by 亚伦负担 on 不飞溅

好的,所以首先,让我们暂时放下电脑谈话。我从 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 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/23048/22130913

posted @ 2022-09-09 13:23  哈哈哈来了啊啊啊  阅读(42)  评论(0编辑  收藏  举报