【问题标题】:Count repeating element sequence in an unsorted array (Java)计算未排序数组中的重复元素序列(Java)
【发布时间】:2020-11-29 06:47:12
【问题描述】:

我需要一个函数,它接收一个 arrayList 并返回一个新的具有相同大小的整数 arrayList。他的元素将表示原始数组中索引 i 中的值的重复序列数(出现次数)。

1 次单次出现也将被计为一个序列。 例如:arr [1, 1, 0, 1] -> 元素 '1' 出现 2 次。

  • 输入:它不一定是排序数组。
  • 在进程结束时保持数组的内容不变。
  • 该函数应使用 Java 编写。

函数示例:

arr [3,0,1,2,1,1,1,3] ▪︎ 输入:(arr) ▪︎ 输出:newArray [2,1,2,1,2,2,2,2] 因为'3'在一个序列中出现2次,'0'出现1次,等等......

arr [1,0,1,2,1,3] ▪︎ 输入:(arr) ▪︎ 输出:newArray [3,1,3,1,3,1]

arr [1,0,0,2,1,3,0] ▪︎ 输入:(arr) ▪︎ 输出:newArray [2,2,2,1,2,1,2]

【问题讨论】:

  • 你有什么尝试吗?
  • 请发布您目前拥有的内容,以及您具体收到的错误。 StackOverflow 旨在回答编程问题,而不是为你做作业。

标签: java arrays sequence


【解决方案1】:

你可以这样做 O(n) 时间复杂度:

步骤 1 使用变量“prev”检查前一个元素,将其初始化为 false/0。 第 2 步只要找到要检查的元素(比如 x)就遍历数组,然后在 prev 为 false 时增加计数,否则在数组中向前移动。

【讨论】:

  • 你能写出函数吗?
【解决方案2】:

此任务类似于数组/列表中元素的常见计数频率,但是,相邻元素(子序列)应计为 1。也就是说,在计数频率时,如果前一个元素相同,则 delta 为 0作为当前的。

要使用 Java Stream 解决这个任务,我们需要实现:

  • Collector类累加最终值和索引列表,包括merge方法添加索引和频率。
static class CollectorList {
    int sum;
    List<Integer> indexes = new ArrayList<>();
    
    public CollectorList(List<Integer> h) {
        this.indexes.add(h.get(0));
        this.sum += h.get(1);
    }
    
    public CollectorList merge(CollectorList next) {
        this.sum += next.sum;
        this.indexes.addAll(next.indexes);
        return this;
    }
}

那么获取自定义频率列表的方法可以实现如下:

public static List<Integer> getFrequencyList(int ... arr) {
    return new ArrayList<>(
        IntStream.range(0, arr.length)  // stream of indexes
                 .mapToObj(i -> Map.entry(
                     arr[i],            // key: current element
                     Arrays.asList(i, i > 0 && arr[i] == arr[i - 1] ? 0 : 1))) // store index and delta
                 .collect(Collectors.toMap(
                     Map.Entry::getKey, // for array elements
                     e -> new CollectorList(e.getValue()), // init collector of helper 
                     CollectorList::merge   // and merge
                 ))
                 .values() // get Collection<CollectorList>
                 .stream() // convert CollectorList back to index -> frequency
                 .flatMap(c -> c.indexes.stream().map(i -> Map.entry(i, c.sum)))
                 .collect(Collectors.toMap(
                     Map.Entry::getKey, 
                     Map.Entry::getValue, 
                     (i1, i2) -> i1, TreeMap::new // sort by index
                 ))
                 .values() // frequencies by index
        );
}

为简洁起见,上面的代码使用 Java 9 Map.entry,如果需要兼容 Java 8,可以将其替换为构造 new AbstractMap.SimpleEntry()

测试:

int[][] tests = {
    {},
    {0},
    {1,2,1,2,1,3,1},
    {1,1,0,1},
    {3,0,1,2,1,1,1,3},
    {1,0,1,2,1,3},
    {1,0,0,2,1,3,0}
};
for (int[] arr : tests) {
    List<Integer> result = getFrequencyList(arr);
    System.out.println(Arrays.toString(arr) + " -> " + result);
}

输出

[] -> []
[0] -> [1]
[1, 2, 1, 2, 1, 3, 1] -> [4, 2, 4, 2, 4, 1, 4]
[1, 1, 0, 1] -> [2, 2, 1, 2]
[3, 0, 1, 2, 1, 1, 1, 3] -> [2, 1, 2, 1, 2, 2, 2, 2]
[1, 0, 1, 2, 1, 3] -> [3, 1, 3, 1, 3, 1]
[1, 0, 0, 2, 1, 3, 0] -> [2, 2, 2, 1, 2, 1, 2]

【讨论】:

  • 这看起来很有希望。谢谢!但是有没有办法做到这一点而不必创建2个类?那会更大。
  • Helper 类可以替换为列表(例如Arrays.asList(i, i &gt; 0 &amp;&amp; arr[i] == arr[i - 1] ? 0 : 1)))或数组,但无论如何都需要Collector 类来封装频率计数并维护索引列表。跨度>
猜你喜欢
  • 2016-03-27
  • 2018-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-04
  • 2014-01-02
相关资源
最近更新 更多