【问题标题】:Delete the elements for given number of iterations删除给定迭代次数的元素
【发布时间】:2019-07-01 23:54:29
【问题描述】:

给定一个N 整数数组。遍历整个数组并选择包含相同值的 K 个位置。然后从阵列中删除这些选定的K。如果我们无法选择K 值,则无法从数组中删除任何位置。

任务是在每次迭代后最小化数组中可用的不同整数的数量。

对于给定的Q 查询,每个查询都有一个编号P。对于每个查询,在执行P 迭代后打印数组中存在的不同整数的数量。

1<= N <= 10^6
1<= K <= 10
1<= Q <= 10^5
0<= C <= 10^5
1 <= P <= N

Example:
N=5
K=1
Q=3

Array = [5,0,1,2,1];

Queries (Various P values):
1
5
3

Output:
3
0
1

P=3时的解释:

1. First iteration, we can remove element 1 with value `5`.
2. Second iteration, we can remove element 2 with `0`.
3. Third iteration, we can remove element 4 with value `2`.

最后,数组只包含两个元素,其值为1所以剩余的不同颜色的数量是 1。

这是我尝试过的代码,但卡在如何满足要求上:

static int getDistinctFeatures(int[] array, int size, int K, int P) {
    Map<Integer, Integer> map = new LinkedHashMap<>();
    // Count the occurrence of each element in the array
    for (int i : array) {
        map.put(i, map.getOrDefault(i, 0) + 1);
    }

    Set<Integer> keys = map.keySet();
    List<Integer> keyList = new ArrayList<>(keys);

    int index = 0;

    for (int i = 0; i < P && index < keyList.size(); i++) {
        int key = keyList.get(index);
        index++;
        int count = map.get(key);
        if (count == 1) {
            map.remove(key);
        } else {
            // What to do here
        }
    }
    return map.size();
}

【问题讨论】:

  • 那么如果 k=2 和 Array=[1,1,1,3,3,3],那么 p=1 的答案是什么?是2吗?
  • @mahbubcseju,我也不确定这个输入,考试只提供了 3 个样本输入。我试图先解决这些问题。

标签: java algorithm


【解决方案1】:

这是一个建议的方法。

  1. 构建从valuecount_of_value 的映射
  2. 找出有多少个值的计数不能被k 整除。这个count_incommensurate 是你无法摆脱的值。
  3. 对于剩余的值,创建一个数组,按递增计数,count_of_value / k
  4. 现在创建一个按迭代次数查找有多少可删除值。
  5. 执行查找。

在您的情况下,这些步骤会导致以下结果。初始地图是:

{
    0: 1,
    1: 2,
    2: 1,
    5: 1,
}

所有的值都可以被k=1 整除,所以count_incommensurate = 0

按递增顺序排列的计数数组是[1, 1, 1, 2]

现在我们来到查找数组。它从0 开始,计数总数为4。所以[4, ...。现在我们将每个数字写入减少之前的计数次数,并在 0 处停止。所以我们得到[4, 3, 2, 1, 1]。换句话说

counts: [1, 1, 1, 2   ]
lookup: [4, 3, 2, 1, 1]

如果我们的计数是[1, 2, 3],我们会得到

counts: [1, 2   , 3      ]
lookup: [3, 2, 2, 1, 1, 1]

但回到我们实际得到的。 [4, 3, 2, 1, 1] 是用于我们查找的从 0 开始的数组,最后的所有内容都是 0

现在进行查找。

查找1 加上不相称的给我们3 + 0 = 3

查找5 已结束,因此我们得到0 + 0 = 0

查找3 为我们提供1 + 0 = 1

如果我们用k=2 重复这个练习,我们会发现count_incommensurate3,我们的查找数组最终是[1]。 (零次迭代后,元素1 仍然存在。)由于所有查找都结束了,我们将得到3, 3, 3 作为我们的答案。

这个算法的时间是O(N + Q)。鉴于需要O(N) 来扫描值,O(Q) 来扫描查询,因此您无法通过一个常数因子来真正改进它。需要提到的一个小点是,最初的计数数组(在这种情况下为[1, 2, 1, 1])需要进行排序,这给问题增加了O(N log N) 的时间复杂度。

【讨论】:

  • 数组[4, 3, 2, 1, 1]是如何生成的,请解释一下。我也迷路了,无法理解语句The lookup array is (remember it is a 0-based array) [4, 3, 2, 1, 1]下面的解释如何完成查找1、5、3以及为什么我们将它们添加到不相称
  • 我的意思是,我无法理解第 4 点和第 5 点是如何实现的
  • @learner 我添加了更多解释,说明在这种情况下它们是如何完成的,如果我们有不同的计数数组,它们会有什么不同。希望这会有所帮助。
  • 至于为什么要加上不相称,那是因为我们从来没有去掉任何不相称的元素。我们尝试删除它们,但最终我们会在k 下方找到无法删除的剩余部分。因此,我们正在跟踪我们可以删除多少元素,以多快的速度,并添加我们最后一个元素的数量。
  • @btilly 你能请你这里的代码我在阅读你的解释时错过了。
【解决方案2】:

这是我根据@btilly 建议的算法编写的答案。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;


class Main {
    public static void main(String args[] ) throws Exception {
           
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        String[] num_arr;
        num_arr = br.readLine().split("\\s");
        
        int [] nkq_arr = new int[3];
        for(int i=0;i<3;i++)
        {   
            nkq_arr[i] = Integer.parseInt(num_arr[i]);
        }

        int N = nkq_arr[0];
        int K = nkq_arr[1];
        int Q = nkq_arr[2];
        
        int i = 0,j = 0;

        String[] param_arr;
        param_arr = br.readLine().split("\\s");
        
        int [] arr = new int[N];
        while(i < N)
        {
            arr[i] = Integer.parseInt(param_arr[i]);
            i++;
        }

        int[] queries = new int[Q];
        while(j < Q)
        {
            queries[j] = Integer.parseInt(br.readLine());
            j++;
        }

        for(int c=0;c<Q;c++)
        {
          System.out.println(minFeatures(arr,N,K,queries[c]));
        } 

    }
    static int minFeatures (int [] arr, int N, int K, int query)
    {
      HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
      int count=0;
      for(int i=0;i<N;i++)
      {
        if(!map.containsKey(arr[i]))
        {
          map.put(arr[i],1);
          count++;
        }
        else
        {
          Integer b = map.get(arr[i]);
          b+=1;
          map.replace((Integer)arr[i],b);
        }
      }
      
      List<Integer> relevant_arr = new ArrayList();
      int improper_count=0;
      int relevant_arr_length = 0;

      for(Integer val : map.values())
      {
        if(val%K==0)
        {
          relevant_arr.add(val/K);
          relevant_arr_length++;
        }
        else
        {
          improper_count++;
        }
      }
      Collections.sort(relevant_arr);
      List<Integer> lookUp_arr = new ArrayList();

      int alpha = 0;
      int overall_length=0;

      while(alpha < relevant_arr_length)
      {
        int number_of_times = relevant_arr.get(alpha);
        int beta = number_of_times;

        while(beta > 0)
        {
          lookUp_arr.add(count);
          beta--;
          overall_length++;
        }
        count--;
        alpha++;
      }

      
      if(query > overall_length-1)
      {
        return improper_count;
      }      
      else
      {
        return improper_count + lookUp_arr.get(query);
      }
  }
}

【讨论】:

    【解决方案3】:

    @btilly 建议的算法的 Python 实现。

    from collections import defaultdict
    
    def evaluateMin(arrQ,k,queryArr):
      ans = []
      countMap = defaultdict(lambda : 0)
      for value in arrQ:
        countMap[value] +=1
      
      counts=[]
      presentEveryTime = 0
      for value in countMap:
        if countMap[value] % k != 0:
          presentEveryTime +=1
        else:
          counts.append(int(countMap[value]/k))
    
      # Creating Lookup Array
      counts = sorted(counts)
      lookup = []
      # print(counts)
      appender = len(counts)
      for count in counts:
        for i in range(count):
          lookup.append(appender)
        
        if appender != 1:
          appender -=1
      # print(lookup,presentEveryTime)
      for query in queryArr:
        if query >= len(lookup):
          ans.append(0+presentEveryTime)
        else: 
          ans.append(lookup[query]+presentEveryTime)
    
      return ans
    
    print(evaluateMin([5,0,1,2,1,1,1],2,[1,5,3,0,2]))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-23
      • 2018-07-02
      • 2018-07-18
      • 1970-01-01
      • 1970-01-01
      • 2020-12-08
      • 2022-08-23
      • 1970-01-01
      相关资源
      最近更新 更多