这个问题的核心解法是:通过并查集确定哪些下标可以自由交换,然后对每个连通块内部的元素进行贪心分配。具体的算法思路与Java实现如下。

🧠 核心思路

1. 确定连通块:swaps 中的每对 [p, q] 都代表一条边。使用并查集(Union-Find) 将所有可以互相交换的下标连接起来,形成若干独立的连通块。
2. 连通块内部分配:在一个连通块内,由于元素可以任意排列,为了最大化交替和(偶数位加、奇数位减),贪心策略是:
   · 将最大的元素放在偶数下标(做加法)。
   · 将最小的元素放在奇数下标(做减法)。
3. 计算贡献:对每个连通块,将元素排序后,小的 oddCount 个(奇数位数量)做减法,其余做加法,累加所有块的贡献即为答案。

💻 Java代码实现

```java
class Solution {
    public long maxAlternatingSum(int[] nums, int[][] swaps) {
        int n = nums.length;
        UnionFind uf = new UnionFind(n);

        // 1. 合并所有可交换的下标
        for (int[] s : swaps) {
            uf.union(s[0], s[1]);
        }

        // 2. 按连通块分组,并统计每个块中奇数下标的数量
        Map<Integer, List<Integer>> components = new HashMap<>();
        Map<Integer, Integer> oddCount = new HashMap<>();

        for (int i = 0; i < n; i++) {
            int root = uf.find(i);
            components.computeIfAbsent(root, k -> new ArrayList<>()).add(nums[i]);
            if (i % 2 == 1) {
                oddCount.put(root, oddCount.getOrDefault(root, 0) + 1);
            }
        }

        long ans = 0;
        // 3. 计算每个连通块的最大交替和
        for (Map.Entry<Integer, List<Integer>> entry : components.entrySet()) {
            List<Integer> vals = entry.getValue();
            int root = entry.getKey();
            int oddCnt = oddCount.getOrDefault(root, 0);

            Collections.sort(vals); // 升序排序
            
            // 小的给奇数位(减),大的给偶数位(加)
            for (int i = 0; i < vals.size(); i++) {
                if (i < oddCnt) {
                    ans -= vals.get(i);
                } else {
                    ans += vals.get(i);
                }
            }
        }
        return ans;
    }

    // --- 并查集内部类 ---
    class UnionFind {
        int[] parent;
        int[] rank;

        public UnionFind(int n) {
            parent = new int[n];
            rank = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
        }

        public int find(int x) {
            if (parent[x] != x) {
                parent[x] = find(parent[x]); // 路径压缩
            }
            return parent[x];
        }

        public void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX == rootY) return;
            
            // 按秩合并
            if (rank[rootX] > rank[rootY]) {
                parent[rootY] = rootX;
            } else if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            } else {
                parent[rootY] = rootX;
                rank[rootX]++;
            }
        }
    }
}
```

 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐