[イラスト]細切りアルゴリズムインタビュー一度覚えている:4バイトにインタビュアーが私を打つバッター

会社を破っバイト、すべての秋のリクルート会社、最も重要なアルゴリズムの一つであるべきであり、それぞれの面接はあなたが基本的なアルゴリズムを細切りできるようになる、一度に記録上、この記事で、今日はいくつかのアルゴリズムを尋ねました質問し、私がしている各アルゴリズムの問題の詳細な与えられた最適解は、インタビューのシーンの時に以下に再現しました。読書は、あなたが何かを得るようになります

ふくらはぎのtryナイフ:効果的なかっこ

ほとんどの場合、インタビュアーは非常に難しい質問をしますが、この質問には、多くの場合、より多くの困難な問題を開発することができ、または質問はシンプルに見えるかもしれませんので、あなたは、あまりにも幸せではありませんが、与えられました最適解は確かに簡単ではありません。この質問はこれです

唯一の「(」、「)」文字列の指定した文字列が有効か否かが判断されるが含まれています。注:空の文字列は有効な文字列に属し

示例 1:
输入: "(())"
输出: true
  
 实例 2:
 输入: "())("
输出: false
 

一見すると、この質問は、私はシンプルなので、安定した(インタビュアーがあまりにも嫌いされたとき片側ので、行ってきましたドラゴンクエストハードレベルに属しleetcdoeでDPタイトルのを)。

実際には、20 leetcodeの質問のこの質問簡易版は、簡単なレベルです

unthinkingly直接私はそうスタック解決するために、99%はそれがスタックしてうまくいくと信じて?ここで私は、次の手順を実行し、手順に従って少しバーを言います:

彼らは文字列が検出された横断する1、「(」次のスタックが存在しないと判定された「(」それは出会いを積み重ねてみましょう「)」:

(1)、如果有,则把处于栈顶的 "("  弹出,相当于和 ")" 进行匹配,然后继续往后遍历字符串

(2)、如果没有,则匹配失败。相当于字符串的最前面出现了 ")",显然这是不合理的。

文字列が横断完了すると2は、空の文字列が有効か無効を示している場合、スタックは、空であるか否かが判断されます。

アカウントに取るためには、白、私も,,,,あなたは図が示す描いた私の良心を与えます。

ここに画像を挿入説明

コードを以下に示し(Javaは、Javaは読んで学ぶことはできませんが)

public static boolean isValid(String s){
    if(s == null || s.length() < 1)
        return true;
    int n = s.length();// 字符串长度
    // 创建一个栈来装字符
    Stack<Character> stack = new Stack<>();
    // 遍历字符串
    for(int i = 0; i < n; i++){
        // 获取字符串的第 i 个字符
        char c = s.charAt(i);
        if(c == '('){
            stack.push(c);
        }else{
            if(stack.isEmpty())
                return false;
            else
                stack.pop();
        }
    }
    // 判断是否为空
    if(stack.isEmpty())
        return true;
    
    return false;
}

第二に、最適化

そして、インタビュアーが宇宙の複雑さのこの質問はO(n)が私を尋ね、私はそれを最適化することができれば尋ねましたか?

あなたが最初の20個の質問のleetcodeを行っている場合は正直に言うと、それはあなたの心かもしれその質問は、最適解のスタックに対処することであるため、必ずしも指示されます。しかし、この質問は、簡略化されたバージョンに属し、実際には、O(1)にスペースの複雑さを最適化することができ、我々はああ、考えることができます。

私たちは店内スタックのである同じ文字「(」実際には、我々はスタックを置き換えるために変数を使用することができ、この変数レコード番号「(」遭遇「は(」変数"が遭遇インクリメントされ)「1マイナス変数、スタックの値が空であること0変数と等価です。

その時私は、なぜ私の心はほとんど、かなりすぐにこの方法、とても良いコードを変更する分を知らない、として、次のとおりです。

public static boolean isValid(String s){
    if(s == null || s.length() < 1)
        return true;
    int n = s.length();// 字符串长度
    // 用来记录遇到的 "(" 的个数
    int sum = 0;
    // 遍历字符串
    for(int i = 0; i < n; i++){
        // 获取字符串的第 i 个字符
        char c = s.charAt(i);
        if(c == '('){
            sum++;
        }else{
            if(sum == 0)
                return false;
            else
                sum--;
        }
    }
    return sum == 0 ? true : false;
}

この方法は、次いで、時間計算量はO(N)であり、空間的な複雑さはO(1)です。

第三に、最大有効ブラケット

そして、インタビュアーは、次のように質問が読んで、この質問の難易度を高めるために継続していきます

のみを含む文字列「(」と「」)指定された、最長有効括弧を含む部分文字列の長さを見つけます。

示例 1:

输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:

输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

実際には、この質問は、元のタイトル、最初の32個の質問のleetcodeで、難易度は難しいです。

私は深刻な表現と考えるように装って、微笑んで、前に行っているので、この質問は、その後すぐにアイデアを提供し、私はちょうど使用し始めた法律は暴力です。

1.暴力行為

暴力は最初の文字の始まりであること、実際には非常に簡単である最長の効果的な括弧の最初の文字として、そして3番目の文字列を横断する文字列、最長の有効括弧の最初の文字として2番目の文字を通過するのは、文字......

たとえば、= S "())(())"。

最初の文字、そして、最大= 2(第三の出会いの文字「)」のように、最初の文字まで一致しません)
どうやら最初の文字、そして、最大= 0(先頭に「)」として第2の文字、何が一致しません)
最初の文字は、MAX = 0のように3番目の文字であり
、次に、最初の文字として4番目の文字。4 =最大
.....
このアプローチの時間複雑度はO(N ^ 2)スペースの複雑さはO(1)であります

上記したような基本的な質問、しかし、やるのnトラバーサル。

そして、インタビュアーは尋ねたが、また、それを最適化?

最適化尋ね知っていた、と私は自分自身にこの質問をした前に、その瞬間のために、すぐに最適化を与えると考えているふり。

2、最適化

この質問は、我々はまだスタックを使用するのですバージョンが、時間の積み重ね、聞かせしないように「(」スタックを最適化しますが、次のように「(」添字スタックをしてみましょう:

1、-1最初のスタックに。(?知っているあなたの後ろを参照してください理由については)
「(」私たちはその意志それぞれの出会いのために,, 2 指標スタックに。
3、各出会いのために「)」、我々はポップ要素および現在の要素Zhanding インデックスポップアップ要素の下添字の差として得られた、現在有効な文字列の長さのブラケット

このように、我々は、サブの有効長さを計算し、最終的には、サブストリングの最長有効長に復帰し続けます。

あなたは、読むことができませんか?右図の例では、例として、S =「())(())」について、いくつかを描く私を取得し、効果的なの最長の文字列の度合いを保持する変数maxと、私は現在の文字列のインデックスを表し、

0、初期化:最大= 0; iが0を=。-1スタックに
ここに画像を挿入説明

図1は、iが0 = [I] = '('、iは0図面を=添字sは
ここに画像を挿入説明

2、i = 1,s[i] = ')',出栈; i - 栈顶元素 = 1 - (-1) = 2,此时 max = 2
ここに画像を挿入説明
3、i = 2,s[i] = ')',出栈;这个时候要注意:由于 -1 出栈后,栈顶没有元素了,所以这个时候我们必须把 ')' 的下标入栈,相当于最开始的初始化。
ここに画像を挿入説明
4、i = 3,s[i] = '(',入栈;
ここに画像を挿入説明
5、i = 4,s[i] = '(',入栈;
ここに画像を挿入説明
6、i = 5,s[i] = ')',出栈;i - 栈顶 = 5 - 3 = 2;此时 max = 2;
ここに画像を挿入説明
7、i = 6,s[i] = ')',出栈;i - 栈顶 = 6 - 2 = 4;此时 max = 4;
ここに画像を挿入説明
8、遍历结束,最长有效括号为 4。

看不大懂?没事,看下代码加深理解勒,代码如下:

public int longestValidParentheses(String s) {
    int max = 0;
    Stack<Integer> stack = new Stack<>();
    stack.push(-1);
    for (int i = 0; i < s.length(); i++) {
        if (s.charAt(i) == '(') {
        //下标入栈
            stack.push(i);
        } else {
        // 出栈
            stack.pop();
            // 看栈顶是否为空,为空的话就不能作差了
            if (stack.empty()) {
                stack.push(i);
            } else {
            // i - 栈顶,获得档期有效括号长度
                max = Math.max(max, i - stack.peek());
            }
        }
    }
    return maxans;
}

这种做法的时间复杂度为 O(n),空间复杂度为 O(n),能想到用栈来处理,算是很不错的了。

4、最后一击

我以为我给出这个解法算是可以的了,面试官应该换一道题的了,然后,面试官又来了一句:还能再优化吗?。这个时候我陷入了沉思.......

看文章的各位大佬们可以想一想在空间上是否还能优化,因为在时间上是不可能优化的了。

想了一会,居然不可以用栈,优化的方案肯定是类似于上面那道题一样,用记录数量的变量来代替栈,然后就被我想出了,具体如下:

实际上,这道题仍然可以像上面那样,用变量来代替栈来优化,不过这个时候我们需要两个变量,我们假设变量为 left 和 right。

我们在从从左到右遍历字符串的过程中,用 left 记录 '(' 的数量,用 right 记录 ')' 的数量。并且在遍历的过程中:

1、如果 left == right,显然这个时候 right 个 ')' 都将一定能够得到匹配。所以当前的有效括号长度为 2 * right。然后更新 max。

2、如果 left < right,显然这个时候部分 ')' 一定得不到匹配,此时我们把 left 和 right 都置为 0。

当遍历完字符串,我们是否就得到最大长度的有效括号了呢?大家可以想一下

答是不可以的,我们还需要从右到左遍历计算一下。

为什么呢?

因为实际上 '(' 和 ')' 其实是等价的,为什么就不可以倒过来遍历计算呢?所以,千万别忽略了哈。

最后的代码如下:

public int longestValidParentheses(String s) {
    if(s == null || s.length() < 1)
        return 0;
    int left = 0, right = 0, max = 0;
    // 从左到右
    for (int i = 0; i < s.length(); i++) {
        if (s.charAt(i) == '(') {
            left++;
        } else {
            right++;
        }
        if (left == right) {
            max = Math.max(max, 2 * right);
        } else if(right > left){
            left = right = 0;
        }
    }
    left = right = 0;
    // 从右到左
    for (int i = s.length() - 1; i >= 0; i--) {
        if (s.charAt(i) == '(') {
            left++;
        } else {
            right++;
        }
        if (left == right) {
            max = Math.max(max, 2 * left);
        } else if (left > right) {
            left = right = 0;
        }
    }
    return max;
}

这种做法的时间复杂度为 O(n),空间复杂度为 O(1)。

总结

说时候,最后一种方法还是比较难想到了,从这次面试中也可以看出,千万不要看一道题很简单,有些题要做出来很简单,但是,如果要以最优解的方式做出来,难度马上指数上升。。

如果你后面看不大懂,建议多看几遍哦,这道题考的频率还是挺高的,主要是可以做的方法多,每种方法的效率又不一样,不过我这里必须给你们的提醒,就是平时在做题的时候,一定要寻找最优解,而不是 ac 了就不管了,应该多看看别人的解法。

有收获?希望老铁们来个三连击,给更多的人看到这篇文章

1、親指アップより多くの人々が記事を参照できるように、
「オリジナルのマイクロチャネル公共番号心配2を、コードの農家を強制するのは難しいコンピュータ(コンピュータ・ネットワーク・オペレーティング・システム+データベース+ + Linuxなど)、およびアルゴリズムの基本的な知識を統合するためには、」、最近、「マイクロチャネル公共番号開かれたコードの農家を強制するのは難しい、喜喜をアルゴリズムに関連する記事を説明する上で興味を持っ缶フォーカス、フォーカスを」。背景返信「電子書籍含むあなたの電子書籍まくるの選択を送信するために」、高品質の電子書籍のスキルのすべての種類を

おすすめ

転載: www.cnblogs.com/kubidemanong/p/11949244.html