📌  相关文章
📜  可被给定数 k 整除的链表的最大和最小元素(1)

📅  最后修改于: 2023-12-03 15:07:27.312000             🧑  作者: Mango

可被给定数 k 整除的链表的最大和最小元素

在链表问题中,如何处理满足特定条件的子链表是一个常见问题。可被给定数 k 整除的链表的最大和最小元素,是一道利用前缀和来解决的经典问题。

题目描述

给定一个长度为 n 的整数链表和一个整数 k,请找出链表中满足以下条件的最大和和最小元素:

  1. 元素之和可被 k 整除;
  2. 元素个数最小。
解题思路

链表上的前缀和及取模运算是解决此类问题的通用方法。使用前缀和可以将求和问题转化为相减问题,使用取模运算可以将求余问题转化为相减问题。

为了找到满足条件的最小元素,我们可以对链表进行一次前缀和处理,得到每个节点的前缀和 p[i],则节点 i 到节点 j 的元素和为 p[j] - p[i-1]。接着,我们可以枚举起点 i 和终点 j,找出满足条件的最小元素。

为了找到满足条件的最大和,我们也可以先对链表进行一次前缀和处理,得到每个节点的前缀和 p[i],则节点 i 到节点 j 的元素和为 p[j] - p[i-1]。接着,我们可以从前往后遍历链表,维护一个最大前缀和 max_prefix_sum 和一个最小前缀和 min_prefix_sum,每次计算当前节点到之前某个节点的前缀和的差值(即可被 k 整除的元素之和),并更新最大值和最小值。

代码实现
Python3
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def max_min_sum(self, head: ListNode, k: int) -> List[int]:
        # 前缀和取模
        p = {0: -1}
        cur_sum = 0
        node = head
        while node:
            cur_sum += node.val
            mod = cur_sum % k
            if mod not in p:
                p[mod] = node.val
            else:
                p[mod] = max(p[mod], cur_sum - p[mod])
            node = node.next

        # 最小元素
        min_sum = float('inf')
        for i in range(k):
            if i not in p:
                continue
            if p[i] < min_sum:
                min_sum = p[i]

        # 最大和
        max_sum, min_prefix_sum, max_prefix_sum = 0, 0, 0
        cur_sum = 0
        node = head
        while node:
            cur_sum += node.val
            mod = cur_sum % k
            if mod in p:
                max_sum = max(max_sum, cur_sum - p[mod])
            if cur_sum < min_prefix_sum:
                min_prefix_sum = cur_sum
            if cur_sum > max_prefix_sum:
                max_prefix_sum = cur_sum
            node = node.next
        if max_prefix_sum % k == 0:
            max_sum = max(max_sum, max_prefix_sum - min_prefix_sum)
        return [max_sum, min_sum]
C++
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>

using namespace std;

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    vector<int> maxMinSum(ListNode* head, int k) {
        // 前缀和取模
        map<int, int> p{{0, -1}};
        int cur_sum = 0;
        ListNode *node = head;
        while (node) {
            cur_sum += node->val;
            int mod = cur_sum % k;
            if (!p.count(mod)) p[mod] = node->val;
            else p[mod] = max(p[mod], cur_sum - p[mod]);
            node = node->next;
        }

        // 最小元素
        int min_sum = INT_MAX;
        for (auto &[mod, sum] : p) {
            if (mod == 0) min_sum = min(min_sum, sum);
            else if (p.count(mod)) min_sum = min(min_sum, cur_sum - p[mod]);
        }

        // 最大和
        int max_sum = 0, min_prefix_sum = 0, max_prefix_sum = 0;
        cur_sum = 0;
        node = head;
        while (node) {
            cur_sum += node->val;
            int mod = cur_sum % k;
            if (p.count(mod)) max_sum = max(max_sum, cur_sum - p[mod]);
            if (cur_sum < min_prefix_sum) min_prefix_sum = cur_sum;
            if (cur_sum > max_prefix_sum) max_prefix_sum = cur_sum;
            node = node->next;
        }
        if (max_prefix_sum % k == 0)
            max_sum = max(max_sum, max_prefix_sum - min_prefix_sum);

        return {max_sum, min_sum};
    }
};