【问题标题】:Array with loops Java带有循环的数组 Java
【发布时间】:2016-01-16 23:06:11
【问题描述】:

我想打印将元素放在一个只出现两次的数组中。因此,例如,如果数字 2 出现 3 或 4 次,则不应打印。到目前为止我编写的代码如下。 我的代码中的问题在于循环。例如,对于数字 2,由于 j=i+1 是初始化条件,因此内部循环不会读取第 jth 位置之前的元素——因为索引 6 处有一个 2,所以它不会计算 2s在它之前,使所需条件为真并显示 2。有没有办法解决这个问题?

public class Problem2 {

    public static void exactlytwice(int[] x) {
        int count, j;
        for (int i = 0; i < x.length; i++) {
            count = 0;
            for (j = i + 1; j < x.length; j++) {
                if (x[i] == x[j])
                    count++;
            }
            if (count == 1)   System.out.print(x[i] + " ");
        }
    }

    public static void main(String[] args) {
        int[] x = new int[15];
        x[0] = 2;
        x[1] = 2;
        x[2] = 2;
        x[3] = 13;
        x[4] = 44;
        x[5] = 44;
        x[6] = 2;
        x[7] = 63;
        x[8] = 63;
        x[9] = 90;
        x[10] = 1;
        x[11] = 2;
        x[12] = 150;
        x[13] = 150;
        x[14] = 180;

        exactlytwice(x);
    }
}

【问题讨论】:

  • 您可以将数组中的值映射为出现次数的键,然后使用 value=2 打印映射中的值。
  • 尽管这与您的问题没有太大直接关系,但您可以简单地将数组初始化为以下形式:int[] x = {2, 2, ...};,而不是手动将整数值分配给特定索引(位置)

标签: java arrays loops


【解决方案1】:

除了你写的问题,我看到你的代码更大的问题是它的效率低下。你在这里做一个循环里面的循环,这很慢(o(n^2))。

我的建议是保留一张数字地图->计数,然后只取那些在地图中只出现两次的:

public static void exactlytwice(int[] x) {
    Map<Integer, Integer> counter = new HashMap<>();
    for (int i = 0; i < x.length; i++) {
        if (counter.contains(i)) {
           counter.put(i,1);
        } else {
           counter.put(i,counter.get(i)+1);
        }
    }

    for (Integer i : counter.keyset()) {
        if (counter.get(i) == 2) {
          System.out.println(i);
        }
    }
}

【讨论】:

  • 如果您使用LinkedHashMap,结果将按照数字出现的顺序排列。使用HashMap,顺序是不确定的,本质上是随机的。或者使用TreeMap,数字将按升序排列。
  • 更重要的是,从性能的角度来看,使用Map&lt;Integer, AtomicInteger&gt;,这样就可以增加计数器值而不用装箱新的Integer
  • 顺便说一句,此解决方案不会保留订单。在这种情况下,我们也可以使用排序解决方案 :)
【解决方案2】:
  1. 考虑维护一个单独的数组/列表,以跟踪已计算/打印的所有元素,您可以跳过在数组中再次显示的相同数字。

  2. 或者您可以对数组进行排序,然后执行整个逻辑来检查重复项。

【讨论】:

  • 单独的数组/列表实际上应该是Map&lt;Integer, AtomicInteger&gt;。我喜欢你的第二个选项,假设你被允许修改数组。 :-)
【解决方案3】:

为了完整起见,有一个没有额外地图的解决方案。它仍然是O(n^2),但没有使用额外的内存。它使用了一种有趣的想法。

首先,我们只需要输出第一次出现的数字,每隔一个不相关,因为我们要么有超过 2 个,要么已经输出了第一个。

其次,我们确实可以从 i+1 元素继续,因为此时,数组中不存在等于 ith 的元素。

public static void exactlytwice(int[] x) {
    int count, j;

    TOP:
    for (int i = 0; i < x.length; i++) {
        count = 0;
        for (j = 0; j < i; j++) {
            if (x[j] == x[i])
                // had this number earlier, so go to the next one.
                continue TOP;
        }
        for (j = i+1; j < x.length; j++) {
            if (i != j && x[i] == x[j])
                count++;
        }
        if (count == 1) System.out.print(x[i] + " ");
    }
}

【讨论】:

  • 关于 Dzmitry 代码,数字 2 仍然打印在屏幕上
【解决方案4】:

除了提供的答案之外,还有两种方法可以解决:

  1. 如果允许修改数组,请将已遇到的元素更改为虚拟值,如果遇到则跳过该值。这将时间复杂度从 O(n^2) 降低到 O(n),但会破坏原始数组。当然,这假设可接受的整数仅限于某个集合(感谢@Dzmitry Paulenka 提醒我我没有明确说明这一点)。要保留数组,您可以制作一个副本(尽管空间复杂度变为 O(n) )。

  2. 如果可以接受任何整数,则创建一个 encountered 布尔数组,全部初始化为 false。将原数组中遇到的元素位置改为encountered布尔数组中的true,如果值已经是true,则可以跳过。同样,时间复杂度 O(n),但空间复杂度 O(n),与 1. 的第二种方法不同,不需要限制数字(整数)的允许范围。

  3. 1234563在j&gt;=i(感谢@Nir Levy 指出j&gt;=i 的要求)。这比已经编写的代码(稍微)低效,但时间复杂度保持不变 O(n^2)。

【讨论】:

  • 你的第二个解决方案不好 - 出现两次的数字将被打印两次(一次用于 i>j,一次用于 i
  • 那么dummy value 是什么? :) 如果是int,那么每个值都是有效的。
  • @NirLevy:谢谢。已编辑:)
  • @DzmitryPaulenka:谢谢。我忘了明确说明这一点。已修复 :) (还有另一种没有添加此要求的方法)
【解决方案5】:

使用 Java 8,您可以使用这样的流来实现这一点:

public static void main(String[] args)
{
    List<Integer> list = Stream.of(12,1,3,4,2,3,7,6,7,3,1,8,4,12,33,45,78,36,8)
    .collect(Collectors.groupingBy(x->x, Collectors.summingInt(x->1)))
    .entrySet().stream().filter(x->x.getValue()==2)
    .collect(ArrayList<Integer>::new,(x,y)->x.add(y.getKey()),ArrayList<Integer>::addAll);
    System.out.println(list);
}

结果是:

[1, 4, 7, 8, 12]

【讨论】:

  • 第二个.collect(...);可以是.map(x -&gt; x.getKey()).collect(Collectors.toList());
【解决方案6】:

代码:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class Writer {  
    private int counter; 
    private Random generator = new Random();
    private List<Integer> data = new ArrayList<Integer>();
    private Map<Integer,Integer> map = new HashMap<Integer,Integer>();

public Writer(int n){
    populate(n);
}

private final void populate(int n){
    for(int i = 0; i != n; i++){
        data.add(generator.nextInt(10));
    }
}

private final void reset(){
    this.counter = 0;
}

public final void occurence(){
    for(int dp : data){
        for(int i = 0; i < data.size(); i++){
            if(dp == data.get(i)){
                counter += 1;
            }
        }
        map.put(dp, counter);
        reset();
    }
}

public final void filter(int d){
    for(int key : map.keySet()){
        if(map.get(key) == d){
            System.out.println("Key: " + key + " Value: " + map.get(key));
        }
    }
}

public void rawData(){
    System.out.println(data.toString());
}

public void output(){
    System.out.println(map.toString());
}

开始:

// Create instance of Writer class and generate '100' random numbers
Writer writer = new Writer(100);

// Output raw data          
writer.rawData();

// Process data
writer.occurence();

// Filter numbers with occurence '10'
writer.filter(10);

// Output processed data
writer.output();

输出(来自调用过滤器(10)):

   Key: 3 Value: 10
   Key: 8 Value: 10

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-02
    • 2021-02-26
    • 1970-01-01
    • 2017-05-21
    • 2016-08-08
    • 1970-01-01
    • 2017-07-16
    • 1970-01-01
    相关资源
    最近更新 更多