【问题标题】:ArrayList : Find nth occurrence of an IntegerArrayList : 查找第 n 次出现的整数
【发布时间】:2015-12-04 08:04:33
【问题描述】:

在 ArrayList 中查找第 n 次出现的数字的最佳方法是什么?

我已经知道了什么?

  1. 查找lastIndexOf号码的List接口有方法,在ArrayList类中实现。
  2. 要查找第一次出现,请使用 indexOf 方法。

我在解决什么问题?

在一个问题中,有一个包含不同数字的列表,我必须返回两个数字的索引,其总和等于目标数字。 例如:List = (1,2,1) & target = 2; 现在1 + 1 =2 和答案将是第一个 1 和第二个 1 的索引。

注意:我已经解决了这个问题,我需要回答这个问题 顶端。 Check Solution

我做了什么?

  public static void main(String[] args)
  {
    List<Integer> list = new ArrayList<Integer>();
    list.add(1);
    list.add(2);
    list.add(1);
    int length = list.size();
    int firstIndex = list.indexOf(1) + 1;
    int secondIndex = firstIndex + list.subList(firstIndex, length).indexOf(1) + 1;
    System.out.println(firstIndex);
    System.out.println(secondIndex);
  }

【问题讨论】:

  • 假设您最好的意思是高效,您希望从 O(n^2) 的时间复杂度降低到较低的时间复杂度。检查我的 O(n*logn) 答案
  • 您的解决方案不是最有效的。请参阅My Solution,它实现了@DiegoMartinola 的想法。老实说,我并没有窃取 Diego 的想法,而是我独立提出的。

标签: java arraylist sublist


【解决方案1】:

"所有数字相等的列表" --> {n,n,...,n,n}。

“我必须返回前两个数字的索引,其和等于目标数字”让我们假设 target=x。 由于您的列表中充满了相同的数字,如果 x/2=n 您的索引将是 0 和 1,如果 x/2 !=n 您将没有任何匹配项


问题版之后


    int length=10;
    int target=100;
    int[] tab1= new int[length];
    Object[] tab2= new Object[length];
    Object[] tab2Sorted= new Object[length];

    for (int i = 0; i < tab2Sorted.length; i++) {
        for (int j = i; j < tab2Sorted.length; j++) {
            if(tab2Sorted[i]+tab2Sorted[j]==target){
                //do what you want on objects to get back indexes
            }

        }
        //As tab3 is sorted you dont have to read all the array
        if(tab2Sorted[i]>target/2){
            break;
        }
    }

您只需将 tab2 和 tab2Sorted 类型从 Object 更改为自定义类型,从第一个选项卡中保存 int 和他的索引

【讨论】:

  • 它不一定充满相等的数字。数字也可以不同。
  • 不要学究,但这应该是评论而不是答案
【解决方案2】:

对于你标题中的问题,你可以用一个循环和List的subList方法一起使用:

public static void main(String[] args)
{
    List<Integer> list = new ArrayList<Integer>();
    list.add(1);
    list.add(1);
    list.add(1);

    int n = 2;
    int index = -1;
    List<Integer> subList = list;

    for( int i = 0; i < n; i++)
    {
        index = subList.indexOf( 1);

        if( index == -1)
            break;

        System.out.println( i + "th index: " + index);
        subList = subList.subList( index+1, subList.size());
    }
}

对于真正的问题,查找列表中第 n 次出现的数字并不是一种可靠的方法,您假设重复的数组元素是目标数字的除数。

【讨论】:

  • 这与我在问题中使用的逻辑相同。有什么区别吗?
【解决方案3】:
public static int nthIndexOf(List<Integer> list, int needle, int n){
    for (int i = 0; i < list.size(); i++) {
        if (list.get(i) == needle) {
            n--;
            if (n == 0) {
                return i;
            }
        }
    }
    return -1;
}

道具Jon Skeet

【讨论】:

  • 此代码返回给定整数第 n 次出现的位置,看起来与 OP 的问题没有太大关系。
  • 是的,但这是一个误导性的标题。在问题中,他具体说明了什么是“真正的”问题。这是一个红色/蓝色问题恕我直言的示例(即,他询问某事但问题是其他问题)。
【解决方案4】:

假设你的列表不是一个列表,而是一个数组(一旦你完成插入,一个数组列表基本上就是一个数组)。

还假设您不想找到总和为 X 的前两个数字的索引,而只想找到两个数字(如果有的话)。

有一个简单的解决方案需要 O(n^2) 时间,您只需将每个数字与后面的所有数字进行迭代,然后检查总和。

更好的方法是对数组进行排序(需要 O(n*logn))。现在,您可以对每个数字在数组中进行二进制搜索以查找其补码,即如果将其相加将导致 X 的数字。这需要 n(每个数字)* log n(二进制搜索其补码) .

但是我们不能排序,因为我们想要索引!或者我们不能?

如果我们创建一个数组的副本,而不仅仅是值,存储一对值 + originalPosition:

class PosAndValue {
  public final int value;
  public final int pos;
  public PosAndValue(int v, int p) {
    value = v;
    pos = p;
  }
} 

我们现在可以将这些 PosAndValue 的数组按其值排序,执行刚才提到的算法,然后检索原始位置(即索引),所有这些都在 n*logn 时间复杂度(和 n 空间复杂度)。

我相当有信心,就复杂性而言,您不能让它“更快”得多。请注意,这并不意味着代码在任何情况下都会更快,而是说,对于足够大的输入(即“足够大”的数组),它会更快!对于小输入,例如您的示例,所有这些开销实际上可能会使代码变慢!

如果您知道输入的范围有限,您可以做得更好,然后对值执行布尔位图 O(n),但这是一个未指定的约束!

【讨论】:

  • 原来的问题是在 O(n) 时间复杂度内解决的。在这里查看我的代码pastebin.com/HwV5w0cW。请检查代码的 else 部分,该部分用于处理总和为目标的数字相等的情况。
  • @amit_yo 我认为您低估了 indexOf 实际上是一个 O(n) 复杂度调用的事实,并且您在所有值的 for 循环中调用它,从而使其成为 O(n^ 2)。此外,您在输入上有一个双重嵌套,这也是 O(n^2)
  • 是的,你是对的,但是 indexOf() 调用了两次,内部 for 循环运行一次,之后代码中断。所以,我认为它是 O(n)。
  • @amit_yo 你有一个 list.add(a.indexOf(diff) + 1);立即在你的 foreach 循环内。那是 n^2,因为它将为每个数字 (n) 调用,并且将花费您 n。在 O(n) 中解决此问题的唯一方法是您知道输入中值的范围并使用位图。这确实是一个已知问题(经典面试问题)。
  • @amit_yo - indexOfO(n) 所以你的解决方案至少是 O(n^2)。 Diego 的想法(和我的实现)在排序后的数组上使用 binarySearch 进行内部搜索,O(n log(n)) 也是如此。
【解决方案5】:
  public static void main(String[] args)
  {
    Integer[] numbersList = {1,2,3,4,5,6,7,8,9,10}; //Load your Array here
    List<Integer> list = Arrays.asList(numbersList);
    int targetNumber = 8;  //Load your targetNumber here

    int currrentVal = 0;
    int nextVal = 0;
    int i = 0;
    int j = 0;
    boolean found = false;
    for(i=0;i<list.size();i++) {
        currrentVal = list.get(i);          
        for(j=currrentVal+1;j<list.size();j++) {
            nextVal = list.get(j);              
            if(targetNumber == currrentVal+nextVal) {
                found = true;
                break;
            }
        }
        if(found) {
            break;
        }
    }
    if(found) {
        System.out.println("firstIndex  : "+i);
        System.out.println("secondIndex : "+j);
    } else {
        System.out.println(" No match found");
    }
  }

【讨论】:

    【解决方案6】:

    你可以构建这样的东西

    List<Integer> numbers = new ArrayList<>(); // your list of numbers. Let's say it's {1, 1, 4, 5, 4}
    numbers.add(1);
    numbers.add(1);
    numbers.add(4);
    numbers.add(5);
    numbers.add(4);
    SparseArray<Set<Integer>> occurrences = new SparseArray<>();
    for (int i = 0; i < numbers.size(); i++) {
        if (occurrences.indexOfKey(numbers.get(i)) < 0) {
            occurrences.put(numbers.get(i), new HashSet<Integer>());
        }
        Set<Integer> ints = occurrences.get(numbers.get(i)); // get current set
        ints.add(i); // add your new found one
        occurrences.put(numbers.get(i), ints); // put it back into your occurrences set
    }
    

    然后它将为您提供原始数字的 SparseArray 以及这些数字的集合从您的原始数组列表中出现索引。

    {1=[1, 0], 4=[4, 2], 5=[3]}
    

    【讨论】:

      【解决方案7】:

      这应该是最有效的。它使用您的数组的排序版本(维护对原始偏移量的引用)和Collections.binarySearch,这应该提供最佳性能。

      private Integer[] addsUp(List<Integer> numbers, int value) {
          // Hold the value and it's original offset.
          class No implements Comparable<No> {
      
              final int n;
              final int o;
      
              public No(int n, int o) {
                  this.n = n;
                  this.o = o;
              }
      
              public No(int n) {
                  this(n, -1);
              }
      
              @Override
              public int compareTo(No o) {
                  return Integer.compare(n, o.n);
              }
      
              @Override
              public String toString() {
                  return "{" + n + " @ " + o + "}";
              }
          };
          // Build my list.
          List<No> myNumbers = new ArrayList(numbers.size());
          for (int i = 0; i < numbers.size(); i++) {
              myNumbers.add(new No(numbers.get(i), i));
          }
          // Start sorted.
          Collections.sort(myNumbers);
          // Upper limit of my search.
          int max;
          // Find the value in the numbers.
          No no = new No(value);
          int spot = Collections.binarySearch(myNumbers, no);
          // Did we find it?
          if (spot < 0) {
              // Not found - but this number is nearest to value.
              max = -spot - 1;
          } else {
              // Found ! No number higher than that is relevant.
              max = spot;
          }
          // For each start number.
          for (int first = 0; first < max; first++) {
              No remainder = new No(value - myNumbers.get(first).n);
              // Does that number appear in the list.
              int second = Collections.binarySearch(myNumbers, remainder);
              if (second >= 0) {
                  // Found second number! Return original offsets.
                  return new Integer[]{myNumbers.get(first).o, myNumbers.get(second).o};
              }
          }
          return null;
      }
      
      public void test() {
          List<Integer> numbers = Arrays.asList(1, 2, 1);
          Integer[] two = addsUp(numbers, 2);
          System.out.println("two = " + Arrays.toString(two));
          Integer[] three = addsUp(numbers, 3);
          System.out.println("three = " + Arrays.toString(three));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-10
        • 1970-01-01
        • 1970-01-01
        • 2011-02-04
        • 1970-01-01
        • 1970-01-01
        • 2016-01-16
        相关资源
        最近更新 更多