【问题标题】:How to divide array to subarrays with the least sum如何将数组划分为总和最小的子数组
【发布时间】:2021-12-09 11:44:18
【问题描述】:

给定一个整数数组arr和一个正整数m,你的任务是找出每个长度为的连续子数组中最常见元素的频率marr.

返回子数组元素中这些最高频率的数组,按相应子数组的起始索引排序。您可以查看示例部分以获得更好的理解。

例子

对于 arr = [1, 2] 和 m = 2,输出应该是
子数组发生次数(arr, m) = [1].

示例 1

arr 只包含一个长度为 m = 2 - arr[0..1] = [1, 2] 的连续子数组。此子数组包含 2 个最频繁的元素 - 1 和 2,它们的频率均为 1。
所以,答案是 [1]。

对于 arr = [1, 3, 2, 2, 3] 和 m = 4,输出应该是
occurrencesInSubarrays(arr, m) = [2, 2].

示例 2

arr 包含两个长度为 m = 4 的连续子数组:

arr[0..3] = [1, 3, 2, 2] 只包含一个最频繁的元素 - 2,其频率为 2。
arr[1..4] = [3, 2, 2, 3] 包含两个最频繁的元素 - 2 和 3,它们的频率都是 2。
将两个子数组的答案放在一起,我们得到数组 [2, 2]

对于 arr = [2, 1, 2, 3, 3, 2, 2, 2, 2, 1] 和 m = 3,输出应该是
occurrencesInSubarrays(arr, m) = [2, 1, 2, 2, 2, 3, 3, 2]。

示例 3

arr 包含 8 个长度为 m = 3 的连续子数组:

arr[0..2] = [2, 1, 2] 只包含一个最频繁的元素 - 2,其频率为 2。
arr[1..3] = [1, 2, 3] 包含三个最常见的元素 - 1、2 和 3。
它们的频率都是 1。
arr[2..4] = [2, 3, 3] 只包含一个最频繁的元素 - 3,它的频率是 2。
arr[3..5] = [3, 3, 2] 只包含一个最频繁的元素 - 3,它的频率是 2。
arr[4 ..6] = [3, 2, 2] 只包含一个最频繁的元素 - 2,其频率为 2。
arr[5..7] = [2, 2, 2] 只包含一个最频繁的元素 - 2,它的频率是 3。
arr[6..8] = [2, 2, 2] 只包含一个最频繁的元素 - 2 ,其频率为 3。
arr[7..9] = [2, 2, 1] 仅包含一个最频繁的元素 - 1,其频率为 2。

将两个子数组的答案放在一起,我们得到数组 [2, 1, 2, 2, 2, 3, 3, 2]。

我的方法是使用两个哈希图。一个作为每一行的队列,一个保存每一行的总和。但它仍然是错误的。任何人都可以解决这个问题吗?

【问题讨论】:

  • 请格式化您的帖子以提高可读性,并分享您认为自己解决问题的最佳尝试,并描述出了什么问题或让您感到惊讶的地方。 stackoverflow.com/help/how-to-ask
  • 考虑一下这个问题,看来它可以在一行短的 Python 代码中解决。
  • 标题和最后一句似乎描述了与帖子其余部分不同的问题。帖子中描述的问题没有提到最小化或求和,只是计算滑动窗口上的频率。这个问题是测试你是否可以实现一个频率计数器;相关数据结构见the collections library
  • 您的标题与您的实际问题不符。此外,对于arr[7..9] = [2, 2, 1],最常见的元素是 2,而不是 1。

标签: python arrays algorithm dynamic-programming


【解决方案1】:

您可以使用字典来跟踪最后一个 m 元素的频率,在您前进时添加元素,同时减去后面的 m 索引元素。

def maxFreqs(arr,m):
    freqs = dict.fromkeys(arr,0)             # frequency counters for range
    result = []
    for i,n in enumerate(arr,1):             # once through the list
        freqs[n] += 1                        # add to frequencies
        if i>m:  freqs[arr[i-m-1]] -= 1      # remove element going out
        if i>=m: result.append(max(freqs.values())) # output max frequencies
    return result

print(maxFreqs([2, 1, 2, 3, 3, 2, 2, 2, 2, 1], 3 ))
[2, 1, 2, 2, 2, 3, 3, 2]

时间复杂度:O(NxM),空间:O(N),其中N是列表的大小,M是子数组窗口的长度

【讨论】:

  • 小错字:这一行应该是result..append(max(freqs.values()))
  • 感谢您了解它,当我重命名变量并且没有意识到时,我打破了它)。现已修复
【解决方案2】:

使用两个映射:elt_to_frequency、frequency_to_count。前者跟踪滑动窗口中每个元素的频率,后者跟踪每个频率的计数。

每次滑动窗口移动时都以明显的方式更新。

还要跟踪 max_frequency。如果 elt_to_frequency 比它大,则将其增加到新的 max_frequency。另一方面,如果 frequency_to_count[max_frequency] 降至零,则新的 max_frequency 比旧的 max_frequency 小一。

线性时间,线性空间。

Ruby 代码

def f(arr, m)
    # Initialize everything
    elt_to_frequency = Hash.new {|h, elt| h[elt] = 0} #Rubyism: new elts default to zero
    frequency_to_count = Hash.new {|h, freq| h[freq] = 0}
    max_frequency = 0
    i = j = -1 # left & right indices
    ans = []
    0.upto(m-1) do |j|
        elt = arr[j]
        add_elt(elt, elt_to_frequency, frequency_to_count)
        max_frequency = [max_frequency, frequency_to_count[elt]].max
    end
    ans << max_frequency
    
    # Now slide the window & make updates. The window is [i, j] inclusive
    m.upto(arr.size - 1) do |j|
        i = j - m + 1
        new_elt = arr[j]
        old_elt = arr[i-1]
        add_elt(new_elt, elt_to_frequency, frequency_to_count)
        subtract_elt(old_elt, elt_to_frequency, frequency_to_count)
        if elt_to_frequency[new_elt] > max_frequency
            max_frequency = elt_to_frequency[new_elt]
        elsif frequency_to_count[max_frequency] == 0
            max_frequency -= 1
        end
        ans << max_frequency
    end
    return ans
end

def add_elt(elt, elt_to_frequency, frequency_to_count)
    elt_to_frequency[elt] += 1
    new_freq = elt_to_frequency[elt]
    frequency_to_count[new_freq] += 1
    frequency_to_count[new_freq - 1] -= 1 # We'll have a negative count for 0 but dont' care
end

def subtract_elt(elt, elt_to_frequency, frequency_to_count)
    elt_to_frequency[elt] -= 1
    new_freq = elt_to_frequency[elt]
    frequency_to_count[new_freq] += 1
    frequency_to_count[new_freq + 1] -= 1 
end

结果

f([2,1,2,3,3,2,2,2,2,1], 3)
=> [2, 1, 2, 2, 2, 3, 3, 2]

【讨论】:

  • 算法部分的解释很棒。如果它带有伪代码会更好... ;-)
  • @DanielHao 我加了代码
【解决方案3】:

方法一:

  1. 创建一个大小为m的窗口。
  2. 在窗口中存储所有元素的频率。
  3. 查找最大频率值。
  4. 向前移动窗口,直到到达数组的末尾。

时间复杂度:O(N2)
空间复杂度:O(N)

    public static int[] occurrencesInSubarrays(int[] arr, int m) {
        int n = arr.length;
        int[] ans = new int[n - m + 1];
        int k = 0;
    
        HashMap<Integer, Integer> freq = new HashMap<>();
        // storing frequencies of each element
        for (int i = 0; i < m; i++)
            freq.put(arr[i], freq.getOrDefault(arr[i], 0) + 1);
    
        for (int i = m; i < n; i++) {
            // find maximum frequency(value) in the hashmap 
            for (int val : freq.values()) {
                ans[i - m] = Math.max(ans[i - m], val);
            }
            // remove element outside of current window
            freq.put(arr[i - m], freq.getOrDefault(arr[i - m], 0) - 1);
            // add new number in the window
            freq.put(arr[i], freq.getOrDefault(arr[i], 0) + 1);
        }
        // again store frequency for last window
        for (int val : freq.values()) {
                ans[n - m] = Math.max(ans[n - m], val);
        }
        return ans;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    • 1970-01-01
    • 2023-03-03
    • 2017-02-02
    • 1970-01-01
    • 2019-07-10
    • 2019-12-18
    相关资源
    最近更新 更多