[LeetCode - クラシック インタビュー 150 の質問 - 8 日目]

11. 最も多くの水を入れる容器

質問の意味:

n length の整数配列が 与えられます height 。n 垂線 があり 、i その線の 2 つの端点は (i, 0) と です(i, height[i]) 。

x 軸とともに最も多くの水を保持できる容器を形成する2 本の線を見つけます 。

コンテナが保存できる水の最大量を返します。

注:容器を傾けることはできません。

【入力サンプル】

[1,8,6,2,5,4,8,3,7]

【出力例】49

問題解決のアイデア: 長方形の最大面積を求めるために変換する

1. ダブル ポインタ i と j はそれぞれ配列の先頭と末尾を指し、i と j の間の距離が長方形の長さになります。

2. 長方形の高さは min(height[i],height[j]) です。

3. 見つけられる最大の領域を格納する変数を定義します。

乾燥開始

class Solution {
    public int maxArea(int[] height) {
        int i = 0,j = height.length - 1;
        int maxWater = 0;
        while(i<j){
            //i不能等于j,等于j只是一条垂线,没有面积,没有办法盛水
            maxWater = Math.max(maxWater,(j-i)* Math.min(height[i],height[j]));
            if(height[i] < height[j]){
                //当左边比右边小时,左指针i往右走,看在减少长度的时候,能不能增加高度
                ++i;
            }else{
                --j;
            }
        }
        return maxWater;
    }
}

タイム: 59.09% を達成

メモリ: 16.11% の差

 15.3つの数字の合計

質問の意味:

整数配列が与えられた場合 、 および を  満たし  および も満たす nums トリプルがあるかどうかを判断します  。お願いします[nums[i], nums[j], nums[k]]i != ji != kj != knums[i] + nums[j] + nums[k] == 0

0 合計が等しく、繰り返されないすべてのトリプルを返します 。

注:回答に重複したトリプルを含めることはできません。

【入力サンプル】

数値=[-1,0,1,2,-1,-4]

[出力サンプル][[-1,-1,2],[-1,0,1]]

問題解決のアイデア: 並べ替え + ダブル ポインター

1. まず配列を昇順に並べ替えます(以下の a、b、c の値は添え字であることに注意してください)

2. a を列挙し、a を求めた後、残りの配列から b(a+1) と c(nums.length-1) を求め、3 つの足し算と 0 の関係を求めます。それらが等しい場合は、fill in この 3 つ組が結果に追加されます。0 より小さい場合は b++、右に移動して大きい方を見つけます。3 つの合計が 0 より大きい場合は、c を減らします。b と c の内部ループ終了条件は、a+b+c=0 ではなく b>=c です。これは、nums[a] が -3、nums[b]、nums[c など、複数の値が存在する可能性があるためです。 ] は -2 と 5、または -1 と 4 のいずれかになります。

3.a は、nums[a] 自体が 0 より大きくなり、ループが終了するまで列挙を続けます。

4. この質問では、繰り返しのトリプルを含めることはできません。a を決定するときは、nums[a-1] の値が nums[a] に等しいかどうかを判断する必要があります。等しい場合、その値は再度使用できません。トラバースを続けます。 bとcも同様です。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        int a,b,c;
        List<List<Integer>> result = new ArrayList<>();
        for(a=0;a<nums.length;a++){
            if(nums[a] > 0) break;
            if(a > 0 && nums[a] == nums[a-1]) continue;//继续寻找下一个a
            b = a+1;
            c = nums.length-1;
            while(b < c){
                int sum = nums[a]+nums[b]+nums[c];
                if( sum < 0){
                    ++b;
                }else if(sum > 0){
                    --c;
                }else{
                    List<Integer> r1 = Arrays.asList(nums[a], nums[b], nums[c]);
                    result.add(r1);
                    while(b < c && nums[b] == nums[b+1]) ++b;
                    while(b < c && nums[c] == nums[c-1]) --c;
                    ++b;
                    --c;
                }
                
            }
        }
        return result;
    }
}

タイム: 91.31% を達成

メモリ: 64.32% 上回る

 209.最小長のサブ配列

質問の意味:

n 正の整数の配列と正の整数 を指定します target 。

配列内でその合計を満たす最小の長さを持つ 連続した部分配列を見つけて 、その長さを返します一致する部分配列がない場合は、 を返します  。 ≥ target  [numsl, numsl+1, ..., numsr-1, numsr]0

【入力サンプル】

ターゲット = 7、数値 = [2,3,1,2,4,3]

【出力サンプル】2

問題解決のアイデア:

暴力的な列挙です。質問の要件に注意してください。ターゲット以上であり、連続した部分配列です。

暴力的な列挙はタイムアウトになります。学習の参照のみを目的としています。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //注意求的是大于等于target,并且是一段连续的子数组
        int result = nums.length + 1;
        int sum = 0;//子序列的数值之和
        int subLength = 0;//子序列的长度
        for(int i=0;i<nums.length;++i){//子序列开始
            sum = 0;
            for(int j = i;j<nums.length;++j){//子序列结束
                sum += nums[j];
                if(sum >= target){
                    //更新结果
                    subLength = j-i+1;
                    result = result < subLength ? result : subLength;
                    break;//从下一个i继续找
                }
            }
        }
        return result == nums.length + 1 ? 0: result;
    }
}

問題解決のアイデア:

ダブル ポインターを使用してスライディング ウィンドウ ソリューションを実装する

1. ポインタ j はウィンドウの終了位置を指します

2. ポインタ i はウィンドウの開始位置を指します。

3. j の位置を列挙し、それらを累積し続けます。sum が target 以上の場合、i を右に移動して、結果がまだ target より大きいかどうかを確認できます。i++ の前に sum-= があることに注意してください。 nums[i] が必要です。これは、右に 1 歩進んだ後、ウィンドウ内の合計に nums[i] が含まれないためです。

4. ウィンドウのスライド処理中、現在の状態の長さが結果より小さいかどうかを常に判断します。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //滑动窗口
        //指针i指向窗口的左边,指针j指向窗口的右边
        //根据窗口的和值是否大于target来判断是否要移动窗口看
        int result = nums.length + 1;
        int sum = 0;//子序列的数值之和
        int subLength = 0;//子序列的长度
        int i =0;//默认每次窗口的其实位置都是第一位
        for(int j=0;j<nums.length;++j){//子序列开始
            sum += nums[j];
            while(sum >= target){
                //当加起来的值大于目标值之后,可以判断此时i能不能往前滑动
                subLength = j-i+1;
                result = result < subLength ? result : subLength;
                sum -= nums[i];
                ++i;//判断i往右滑动一步之后,是否还能符合条件,不能的话,内层while结束,外层j继续滑动
            }
        }
        return result == nums.length + 1 ? 0: result;
    }
}

時間: 99.69% を達成

メモリ: 57.73% の差

 3. 重複する文字を含まない最長の文字列

質問の意味:

文字列を指定して 、繰り返し文字を含まない最長の部分文字 s列の長さを 見つけてください 

【入力サンプル】

s="abcabcbb"

【出力サンプル】3

問題解決のアイデア:

なぜなら、古典的な面接の質問 150 がスライディング ウィンドウにまとめられており、前回の質問 209 が私にとって初めてのスライディング ウィンドウの質問だったので、スライディング ウィンドウを使用して実装されるだろうとすぐに推測できました。

文字を繰り返さないでください。マップの使用を検討し、文字をキーとして使用してください。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.length()==0){
            return 0;
        }
        int i=0;
        int subLength = 0;
        int result = 0;
        Map<Character,Integer> map = new HashMap<>();
        for(int j=0;j<s.length();++j){
            char c = s.charAt(j);
            while(map.containsKey(c)){
                //如果map已经有这个字符了,左指针往右挪一步
                //挪动前需要先删掉
                map.remove(s.charAt(i));
                ++i;
            }
            map.put(c,j);
            result = Math.max(result,j-i+1);
        }
        return result;
    }
}

タイム: ビート 20.12%

メモリ: 41.36% の差

おすすめ

転載: blog.csdn.net/qq_37998848/article/details/132360410