アルゴリズム通関村 - ダブルポインターの魔法の使い方

1.要素の奇数と偶数の動きのトピック

1.1 奇数-偶数で配列をソートする

配列を奇数-偶数でソートする
整数配列 nums を指定し、nums 内のすべての偶数要素を配列の先頭に移動し、その後にすべての奇数要素を移動します。
この条件を満たす配列を答えとして返します。

1.1 左右のポインタ

最初の反応は、左側に偶数、右側に奇数を配置するだけでよく、左端と右端の 2 つのポインターを使用して、同時に中央に移動できます。左の要素が偶数かどうか判断する必要があり、偶数であれば奇数、右の要素が偶数であれば位置が入れ替わりますが、左の要素が偶数であれば左の自己インクリメントはOKですが、右の要素が奇数の場合、それが満たされ、右の要素は自動的に減少します。

public int[] sortArrayByParity(int[] nums) {
    
    
        int left =0;
        int right = nums.length -1;
        while(left<right){
    
    
            if(left<right && nums[left] % 2==0){
    
    
                left++;
            }
            if(left<right && nums[right]%2!=0){
    
    
                right--;
            }
            if(nums[left] %2!=0 && nums[right] %2==0 ){
    
    
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right]=temp;
                left++;
                right--;
            }
        }
        return nums;
    }

時間計算量: O(n)
空間計算量: O(1)

2 配列の回転の問題

2.1 回転配列

配列の
回転 整数の配列 nums を指定して、配列内の要素を k 位置右に回転します。ここで、k は非負の数です。

2.1.1 反転

最初のアイデアは、配列を 1 つずつ反転し、最後の要素を順番に先頭に挿入することです。しかし、この状況の利点は複雑であり、考慮すべきことがたくさんあります。したがって、反転が使用されます。最初にすべての要素が反転され、次に k 要素の前の要素が反転され、k の後の要素も反転されます。ここでは、k を添字、つまり位置 k-1 の要素に変換する必要があります。
ここに画像の説明を挿入

 public void rotate(int[] nums, int k) {
    
    
        k = k% nums.length;
        reverse(nums,0,nums.length-1);
        reverse(nums,0,k-1);
        reverse(nums,k,nums.length-1);
    }

    public void reverse(int [] nums,int start,int end){
    
    
        while(start <end){
    
    
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start+=1;
            end-=1;
        }
    }

時間計算量: O(N) 1 回目の反転は O(N)、2 回目は O(k)、3 回目は O(Nk) 空間計算量: O(1
)

3. 配列の間隔トピック

3.1 サマリー間隔

間隔の要約
繰り返し要素のない順序付けされた整数配列 nums が与えられます。
配列内のすべての数値を正確にカバーする間隔範囲の最小の順序付きリストを返します。つまり、nums の各要素は正確にある範囲の範囲に収まっており、特定の範囲内に収まるが nums に属さない数値 x は存在しません。
リスト内の各範囲 [a,b] は、次の形式で出力される必要があります:
"a->b" if a != b
"a" if a == b

3.1.1 高速ポインタと低速ポインタ

高速ポインタを最後まで行かせます。高速ポインタの後ろの要素が現在の要素と連続していない場合、開始要素と高速ポインタ要素の文字列を返し、このときのスローポインタは最後の要素にジャンプします。高速ポインタの要素位置を次の初期位置として使用します。途中で、現在の速度ポインタが同じ位置にあるかどうかを判断する必要があり、同じ位置にある場合は、要素が 1 つだけであることを意味します。
ここに画像の説明を挿入

public List<String> summaryRanges(int[] nums) {
    
    
        int slow = 0;
        List<String> list = new ArrayList<>();
        for(int fast =0;fast<nums.length;fast++){
    
    
            //fast 向后遍历,不满足条件nums[fast]+1=nums[fast+1],就是不连续的
          if(fast+1 ==nums.length || nums[fast] +1 !=nums[fast+1]){
    
    
              StringBuilder sb = new StringBuilder();
              // 记录下开始元素
              sb.append(nums[slow]);
              if(slow!=fast){
    
    
                  // 记录结束元素
                  sb.append("->").append(nums[fast]);
              }
              list.add(sb.toString());
              // 下一个区间起始位置
              slow =fast+1;
          }
        }
        return list;
    }

時間計算量: O(N)
空間計算量: O(1)

3.2 スペースの欠落

リンク 163 にはメンバーシップが必要です。
基本的には 3.1 と同じですが、不足しているスペースを取得するようになりました。
例: nums[0,1,3,50,75] , lower=0,upper=99
結果は次のようになります: ["2", " 4→49"、"51→74"、"76→99"]

3.2.1 高速ポインタと低速ポインタ

まず第一に、この質問は同じです。高速ポインタを不連続になるまで移動させますが、今度は低速ポインタは必要ありません。高速ポインタ要素と次の位置要素の間のスペース出力を記録するだけですが、次のことが必要です。現在の要素が下限と上限の範囲を超えているかどうかを判断します。

  public static List<String> findNonContiguousSpaces(int[] nums, int lower, int upper) {
    
    
        List<String> list = new ArrayList<>();
        int n = nums.length;

        if (nums[0] > lower) {
    
    
            int start = lower;
            int end = nums[0] - 1;
            list.add(start + "->" + end);
        }


        for (int fast = 1; fast < n - 1; fast++) {
    
    
            int prev = nums[fast] + 1;
            int cur = nums[fast + 1] - 1;
            list.add(prev + "->" + cur);
        }

        if (nums[n - 1] < upper) {
    
    
            int end = upper;
            int start = nums[n - 1] - 1;
            list.add(start + "->" + end);
        }

        return list;
    }

時間計算量: O(n)
空間計算量: O(1)

4. スペースを文字列に置き換えます

4.1 スペースを置換する

スペースの置換
文字列 s 内の各スペースを「%20」に置換する関数を実装してください。

4.1.1 文字列インターセプト

新しい文字列を作成し、char を使用して文字列内の各文字を保存します。文字が空の場合は「%20」を結合し、そうでない場合は直接結合します。

public String replaceSpace(String s) {
    
    
        String rep = "";
        for(int i=0;i<s.length();i++){
    
    
            char c = s.charAt(i);
            if(c == ' '){
    
    
                rep+="%20";
            }else{
    
    
                rep+=c;
            }
        }
        return rep;
    }

時間計算量: O(N^2) は主に文字列を走査し、文字列を再度結合します。
ここに画像の説明を挿入
明らかに、時間と空間の効率は比較的低くなります。

4.1.2 高速ポインタと低速ポインタ

まず、スペースがいくつあるかを計算し、%20 を追加して 3 バイトを占め、1 つのスペースが 1 バイトを占めます。余分な長さはすべて 2 バイトで、合計 2*n バイトが余分になります。次に、文字列バッファの長さを拡張し、新しい文字列の末尾に低速ポインタがあり、元の文字列の末尾に高速ポインタがあります。高速ポインタがスペースに遭遇した場合は、3 文字を使用してスペースを置き換える必要があり、その後、ゆっくりと 3 つの位置に移動します。 fast は、fast が開始位置に到達するまで 1 つの位置を移動します。

 public String replaceSpace(String s) {
    
    
        StringBuffer str= new StringBuffer(s);
        if(str ==null) return null;
        int blankCount =0;
        int len = str.length();
        for(int i=0;i<len;i++){
    
    
            if(str.charAt(i) == ' '){
    
    
                blankCount++;
            }
        }

        int newLength = len+2*blankCount;
        str.setLength(newLength);
        int slow = newLength-1;
        int fast = len-1;

        while(fast>=0 && slow!=fast){
    
    
            char c = str.charAt(fast);
            if(c==' '){
    
    
                fast--;
                str.setCharAt(slow--,'0');
                str.setCharAt(slow--,'2');
                str.setCharAt(slow--,'%');
            }else{
    
    
                str.setCharAt(slow,c);
                fast--;
                slow--;
            }
        }
        return str.toString();
        }

ここに画像の説明を挿入
時間がまだ非常に速いことがわかります。
時間計算量: O(n)。まず文字列を 1 回走査し、スペースの数を見つけて、新しい文字列を展開します。

おすすめ

転載: blog.csdn.net/qq_52843958/article/details/131939472