Zuoshen Advanced Advanced クラス 3 (線形データを記録するための TreeMap シーケンス テーブルの使用、スライディング ウィンドウ、プレフィックスとレコード構造の使用、可能性の破棄)

目次

【事例1】

[タイトル説明]

【アイデアの分析】

【コード】

【事例2】

[タイトル説明]

【アイデアの分析】

【コード】

【事例3】

[タイトル説明]

【アイデアの分析】

【コード】

【事例4】

[タイトル説明]

 【アイデアの分析】

【コード】


【事例1】

[タイトル説明]

【アイデアの分析】

ここでは建物間に重なりがあります。次にアウトライン配列を説明します。そのため、各点の最大高さを知る必要があります。各建物の中央部分の高さは等しいため、この時点でどの建物が最も高いかを知る必要があるだけであり、建物の中央部分の高さは等しいため、開始位置と終了位置のみを気にする必要があります。各建物の。行列を使用してこのような配列を構築できます [配列にはノードが格納され、ノードには位置、持ち上げ状況、高さの 3 つの情報が含まれます] 配列は位置と持ち上げ状況によってソートされます (1) 最初に位置でソートします。昇順 (2) 2 つの位置が同じ場合、開始位置 (上昇の場合) が 1 位となります。

このような配列配列により、高さと見た目の配列表を構築することができ、上昇すればレコードが追加され、下降すればレコードが削除され、レコードが 0 の場合は削除されます。このシーケンステーブルを通じて、現在位置の最大高さを知ることができます(位置と最大高さの関係もシーケンステーブルとして構築して保存し、輪郭を生成する際に輪郭位置の変化が規則的に行われるようにします)。高さの変化を通じて輪郭が変化することを知ることができ、位置と最大高さの順序テーブルから輪郭配列が構築されます。

【コード】

package AdvancedPromotion3;

import java.util.*;

/**
 * @ProjectName: study3
 * @FileName: Ex1
 * @author:HWJ
 * @Data: 2023/9/18 10:27
 */
public class Ex1 {
    public static void main(String[] args) {
        int[][] matrix = {
   
   {2, 5, 6}, {1, 7, 4}, {4, 6, 7}, {3, 6, 5}, {10, 13, 2}, {9, 11, 3}, {12, 14, 4}, {10, 12, 5}};
        List<List<Integer>> ans = getContourMatrix(matrix);
        for (List<Integer> integers : ans) {
            for (int i : integers) {
                System.out.print(i + " ");
            }
            System.out.println();
        }

    }

    public static class Node {
        int x;
        boolean isAdd; // true 表示当前为一个楼的开始, false表示当前地点为一个楼的结束
        int height;

        public Node(int x, boolean isAdd, int height) {
            this.x = x;
            this.isAdd = isAdd;
            this.height = height;
        }


    }

    public static class NodeComparator implements Comparator<Node> {

        @Override
        public int compare(Node o1, Node o2) {
            if (o1.x != o2.x) {
                return o1.x - o2.x;
            }
            if (o1.isAdd != o2.isAdd) {
                return o1.isAdd ? -1 : 1;
            }
            return 0;
        }
    }

    public static List<List<Integer>> getContourMatrix(int[][] matrix) {
        Node[] nodes = new Node[matrix.length * 2];
        for (int i = 0; i < matrix.length; i++) {
            nodes[i * 2] = new Node(matrix[i][0], true, matrix[i][2]);
            nodes[i * 2 + 1] = new Node(matrix[i][1], false, matrix[i][2]);
        }
        Arrays.sort(nodes, new NodeComparator());
        TreeMap<Integer, Integer> heightAndNums = new TreeMap<>();
        TreeMap<Integer, Integer> maxHeight = new TreeMap<>();
        for (Node node : nodes) {
            if (node.isAdd) {
                if (!heightAndNums.containsKey(node.height)) { //如果不存在就新建记录
                    heightAndNums.put(node.height, 1);
                } else {
                    heightAndNums.put(node.height, heightAndNums.get(node.height) + 1);
                }
            } else {
                if (heightAndNums.get(node.height) == 1) { // 如果只剩一条记录了就直接删除
                    heightAndNums.remove(node.height);
                } else {
                    heightAndNums.put(node.height, heightAndNums.get(node.height) - 1);
                }
            }
            if (heightAndNums.isEmpty()) { // 这里通过顺序表记录当前结点的最大高度
                maxHeight.put(node.x, 0);
            } else {
                maxHeight.put(node.x, heightAndNums.lastKey());
            }
        }
        int preHeight = 0;
        int start = 0;
        List<List<Integer>> res = new ArrayList<>();
        for (int x : maxHeight.keySet()) {
            int curHeight = maxHeight.get(x);
            if (preHeight != curHeight) { // 如果高度发生了变化,就构建轮廓
                if (preHeight != 0) { // 如果之前的高度为0, 说明之前的那个地方到现在的地方没有楼
                    res.add(new ArrayList<>(Arrays.asList(start, x, preHeight)));
                }
                preHeight = curHeight;
                start = x;
            }
        }

        return res;
    }
}

【事例2】

[タイトル説明]

【アイデアの分析】

スライディング ウィンドウで解きます。現在のウィンドウの要素の合計が k より大きい場合は l++、k より小さい場合は r++、==k の場合は答えを記録し、r++ とします。

スライディング ウィンドウは正の配列であるため、移動プロセス中に単調性を維持できます。答えが正しいことを確認してください。

【コード】

package AdvancedPromotion3;

/**
 * @ProjectName: study3
 * @FileName: Ex2
 * @author:HWJ
 * @Data: 2023/9/18 11:07
 */
public class Ex2 {
    public static void main(String[] args) {
        int[] arr = {1,2,3,1,1,1,2,1,1,3};
        System.out.println(getMaxLen(arr, 3));
    }

    public static int getMaxLen(int[] arr, int k){
        int l = 0;
        int r = 0;
        int sum = 0;
        int res = -1;
        while (r < arr.length){
            if (sum == k){
                res = Math.max(r - l + 1, res);
                r++;
                if (r == arr.length){
                    break;
                }
                sum += arr[r];
            }
            if (sum > k){
                sum -= arr[l++];
            }
            if (sum < k){
                r++;
                if (r == arr.length){
                    break;
                }
                sum += arr[r];
            }
        }
        return res;
    }
}

【事例3】

[タイトル説明]

順序なし配列 arr を指定すると、要素は正、負、または 0 のいずれかになり、整数 k が与えられます。arr のすべての部分配列の中で、累積和が k に等しい最長の部分配列の長さを求めます。

【アイデアの分析】

ハッシュ テーブルを構築し、その中にプレフィックスの合計を入力し、このプレフィックスの合計のインデックス位置に到達します。k = 5を追加します。

ハッシュ テーブルにはレコード 12,i があります。0--i を示し、すべての要素の合計は 12、トラバーサル内のプレフィックスの合計が 17 で、すべてが j (j > i) の場合、i+1 の累積合計 --- j kであるべきです。答えを記録するだけです。

【コード】

package AdvancedPromotion3;

import java.util.HashMap;

/**
 * @ProjectName: study3
 * @FileName: Ex3
 * @author:HWJ
 * @Data: 2023/9/18 11:17
 */
public class Ex3 {
    public static void main(String[] args) {

    }

    public static int getMaxLen(int[] arr, int k){
        if (arr.length == 0){
            return 0;
        }
        HashMap<Integer, Integer> sumIndex = new HashMap<>();
        sumIndex.put(0, -1);
        int res = -1;
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
            if (sumIndex.containsKey(sum - k)){
                res = Math.max(res, i - sumIndex.get(sum - k));
            }
            sumIndex.put(sum, i);
        }
        return res;
    }
}

  

【事例4】

[タイトル説明]

 【アイデアの分析】

2 つの配列表現を構築します。1 つの配列 minSum[i] は、i から開始して到達できる最も遠い場所を表し、この部分配列の合計を最小化します。minIndex[i] は、i から開始して到達できる最も遠い場所のインデックスを表します私。

たとえば、テーブルの最初の行は順序なし配列 arr を表し、2 行目は minSum を表し、3 行目は minIndex を表します。

3 -2 -4 0 6
-3 -6 -4 0 6
3 3 3 3 4

これを取得した後は配列をいくつかの部分に分割し、minIndex で次の部分の先頭を見つけることができるので、次回は次の部分を追加できるかどうかだけを考えます。

例えば

位置 0 からトラバースを開始し、3 つのパートを追加して位置 k に到達しましたが、次のパートに参加できなかったため、次のパートに参加できるかどうかを確認するために 1 からトラバースを開始しましたデフォルトでは 1-k が正当であるとします。不正な場合は次の部分に追加してはいけないため、その有効サイズは 0-k 未満でなければなりません。最大有効長を見つける必要があるため、次の部分に追加することはできません。有効な解決策であるため、彼は合法であると直接デフォルト設定します。彼が次のエリアに参加できる場合にのみ、可能な回答として考慮されます。これにより、多くの無効な可能性が破棄され、アルゴリズムの複雑さが軽減されます。

【コード】

package AdvancedPromotion3;

/**
 * @ProjectName: study3
 * @FileName: Ex4
 * @author:HWJ
 * @Data: 2023/9/18 12:10
 */
public class Ex4 {
    public static void main(String[] args) {
        int[] arr = {3,-2,-4,0,6};
        System.out.println(getMaxLen(arr, -2));
    }

    public static int getMaxLen(int[] arr, int k){
        int n = arr.length;
        int[] minSub = new int[n];
        int[] minIndex = new int[n];
        minSub[n - 1] = arr[n - 1];
        minIndex[n - 1] = arr[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            if (minSub[i + 1] <= 0){
                minSub[i] = arr[i] + minSub[i + 1];
                minIndex[i] = minIndex[i + 1];
            }else {
                minSub[i] = arr[i];
                minIndex[i] = i;
            }
        }
        int res = 0;
        int p = 0;
        int sum = 0;
        boolean loop =true; // 使第一次进入求解答案时,能正确进入循环
        for (int i = 0; i < n; i++) {
           while (p < n && (loop || sum <= k)){ // 这里不初始化p 和 sum,这样可以舍弃大量不是最优解的解。
               res = Math.max(res, p - i);
               sum += minSub[p];
               p = minIndex[p] + 1;
               loop = false;
           }
           sum -= arr[i];
        }
        return res;
    }
}

 

おすすめ

転載: blog.csdn.net/weixin_73936404/article/details/132962564