【问题标题】:Repeating number in an array数组中的重复数字
【发布时间】:2016-03-18 21:57:05
【问题描述】:

我们得到一个从 1 到 n 的 n 个整数的只读数组。每个整数只出现一次,除了出现两次的 A 和缺失的 B。 返回 A 和 B。 我知道我的解决方案不节省空间,但我想知道为什么我会在以下情况下得到错误的输出:

389, 299, 65, 518, 361, 103, 342, 406, 24, 79, 192, 181, 178, 205, 38, 298, 218, 143, 446, 324, 82, 41, 312, 166, 252, 59, 91, 6, 248, 395, 157, 332, 352, 57, 106, 246, 506, 261, 16, 470, 224, 228, 286, 121, 193, 241, 203, 36, 264, 234, 386, 471, 225, 466, 81, 58, 253, 468, 31, 197, 15, 282, 334, 171, 358, 209, 213, 158, 355, 243, 75, 411, 43, 485, 291, 270, 25, 100, 194, 476, 70, 402, 403, 109, 322, 421, 313, 239, 327, 238, 257, 433, 254, 328, 163, 436, 520, 437, 392, 199, 63, 482, 222, 500, 454, 84, 265, 508, 416, 141, 447, 258, 384, 138, 47, 156, 172, 319, 137, 62, 85, 154, 97, 18, 360, 244, 272, 93, 263, 262, 266, 290, 369, 357, 176, 317, 383, 333, 204, 56, 521, 502, 326, 353, 469, 455, 190, 393, 453, 314, 480, 189, 77, 129, 439, 139, 441, 443, 351, 528, 182, 101, 501, 425, 126, 231, 445, 155, 432, 418, 95, 375, 376, 60, 271, 74, 11, 419, 488, 486, 54, 460, 321, 341, 174, 408, 131, 115, 107, 134, 448, 532, 292, 289, 320, 14, 323, 61, 481, 371, 151, 385, 325, 472, 44, 335, 431, 187, 51, 88, 105, 145, 215, 122, 162, 458, 52, 496, 277, 362, 374, 26, 211, 452, 130, 346, 10, 315, 459, 92, 531, 467, 309, 34, 281, 478, 477, 136, 519, 196, 240, 12, 288, 302, 119, 356, 503, 527, 22, 27, 55, 343, 490, 127, 444, 308, 354, 278, 497, 191, 294, 117, 1, 396, 125, 148, 285, 509, 208, 382, 297, 405, 245, 5, 330, 311, 133, 274, 275, 118, 463, 504, 39, 99, 442, 337, 169, 140, 104, 373, 221, 499, 413, 124, 510, 159, 465, 80, 276, 83, 329, 524, 255, 387, 259, 397, 491, 517, 23, 4, 230, 48, 349, 412, 142, 114, 487, 381, 164, 35, 67, 498, 73, 440, 108, 226, 96, 132, 144, 207, 235, 33, 69, 128, 236, 364, 198, 475, 173, 493, 150, 90, 515, 111, 68, 232, 340, 112, 526, 492, 512, 495, 429, 146, 336, 17, 350, 251, 7, 184, 76, 380, 359, 293, 19, 49, 345, 227, 212, 430, 89, 474, 279, 201, 398, 347, 273, 37, 185, 177, 102, 304, 295, 422, 94, 426, 514, 116, 183, 180, 494, 42, 305, 152, 390, 30, 247, 451, 32, 388, 331, 78, 424, 368, 394, 188, 306, 449, 8, 214, 120, 179, 280, 511, 409, 338, 153, 507, 370, 461, 217, 161, 483, 147, 242, 86, 417, 268, 71, 462, 420, 167, 513, 379, 307, 522, 435, 113, 296, 457, 525, 45, 529, 423, 427, 2, 438, 64, 316, 46, 40, 13, 516, 367, 233, 110, 318, 250, 283, 216, 186, 310, 237, 377, 365, 175, 479, 378, 66, 414, 473, 165, 210, 50, 348, 372, 363, 339, 20, 168, 284, 415, 505, 206, 53, 223, 434, 202, 123, 399, 400, 135, 269, 428, 219, 456, 28, 464, 267, 489, 98, 391, 195, 366, 300, 484, 533, 229, 213, 149, 160, 256, 303, 530, 301, 29, 404, 344, 401, 220, 287, 9, 407, 170, 450, 523, 249, 72, 410, 3, 21, 200, 260

预期输出:

213 87

实际输出:

213 3

到目前为止我尝试过的 Java 代码

public class Solution {
    // DO NOT MODIFY THE LIST
    public ArrayList<Integer> repeatedNumber(final List<Integer> a) {
        int n=a.size();
        int rep=0,b=0;
        int[] arr= new int[n+1];
        for(int i=0;i<n+1;i++) //value i is at index i
            arr[i]=i;
        arr[0]=-1;
        for(int val : a)
        {
            if(arr[val]!=-1)
                arr[val]=-1;
            else
            {
                rep=val;
                break;
            }
        }
        for(int i=0; i<n+1; i++)
        {
            if(arr[i]!=-1)
            {
                b=i;
                break;
            }
        }
        ArrayList<Integer> ans = new ArrayList<Integer>();
        ans.add(rep);
        ans.add(b);
        return ans;
    }
}

【问题讨论】:

  • 我认为你只需要省略第一个中断。
  • This 可能会有所帮助
  • @TheLostMind This 有细微的不同。
  • @laune - 他可以使用 XOR 找到重复的号码。接下来,要找到丢失的数字,他可以这样做(n (n+1)) / 2 - 当前数组的总和
  • @user6038386 请查看我的解决方案。这不是很有效吗?

标签: java


【解决方案1】:

你会发现这样的错误,因为你需要一次完整的遍历数组来检测缺失值。您可以提前停止重复。

for(int val : a){
    if(arr[val]!=-1){
        arr[val]=-1;
    } else {
        rep=val;
        ///////////////// Omit:      break;
    }
}

稍后基本相同的想法,但使用更多的Java,使其更短:

int dup = 0;
int abs = 0;
BitSet present = new BitSet( a.size() + 1 );
for( int x: a ){
    if( present.get( x ) ){
        dup = x;
    } else {
        present.set( x );
    }
}
abs = present.nextClearBit( 1 );

如果你可以修改原始数组(或列表),你可以避免使用一些额外的存储:

int dup = 0;
int abs = 0;
for( int i = 0; i < a.length; ++i ){
    if( a[i] <= 0 ) continue;
    int val = a[i];
    a[i] = 0;
    while( true ){
        if( a[val-1] == -val ){
            dup = val;
            break;
        } else {
            int h = a[val-1];
            a[val-1] = -val;
            if( h == 0 ) break;
            val = h;
        }
    }
}
for( int i = 0; i < a.length; ++i ){
    if( a[i] >= 0 ){
         abs = i+1;
         break;
    }
}

【讨论】:

  • 但我仍然想知道,为什么会这样,您能详细说明一下吗? for "你需要一次完整的遍历数组来检测缺失值" --> 这个循环是为了找到重复的而不是缺失的数字!!
  • 但是你标记了一个数字的地方 - 所以它相当于找到丢失的数字,就像电影中的负片:-)
【解决方案2】:

我将首先使用List.toArray(T[]) 获取一个数组,对数组进行排序,然后迭代 排序 数组一次。比如,

public ArrayList<Integer> repeatedNumber(final List<Integer> a) {
    Integer[] arr = a.toArray(new Integer[0]);
    Arrays.sort(arr);
    Integer[] r = new Integer[2];
    for (int i = 1; i < arr.length; i++) {
        int prev = arr[i - 1];
        if (prev == arr[i]) {
            r[0] = prev;
        } else if (prev != arr[i] - 1) {
            r[1] = prev + 1;
        }
    }
    return new ArrayList<Integer>(Arrays.asList(r));
}

我根据您的输入进行了测试并得到(按要求)

[213, 87]

【讨论】:

  • 为什么要使用 O() 更高的算法?
  • @laune 为什么(过早地)优化?
【解决方案3】:

这是一种解决方案,它不会改变原始列表并仅使用数学来找到丢失的列表。

public static void main(String[] args) {
    find(new int[]{389, 299, 65, 518, 361, 103, 342, 406, 24, 79, 192, 181, 178, 205, 38, 298, 218, 143, 446, 324, 82, 41, 312, 166, 252, 59, 91, 6, 248, 395, 157, 332, 352, 57, 106, 246, 506, 261, 16, 470, 224, 228, 286, 121, 193, 241, 203, 36, 264, 234, 386, 471, 225, 466, 81, 58, 253, 468, 31, 197, 15, 282, 334, 171, 358, 209, 213, 158, 355, 243, 75, 411, 43, 485, 291, 270, 25, 100, 194, 476, 70, 402, 403, 109, 322, 421, 313, 239, 327, 238, 257, 433, 254, 328, 163, 436, 520, 437, 392, 199, 63, 482, 222, 500, 454, 84, 265, 508, 416, 141, 447, 258, 384, 138, 47, 156, 172, 319, 137, 62, 85, 154, 97, 18, 360, 244, 272, 93, 263, 262, 266, 290, 369, 357, 176, 317, 383, 333, 204, 56, 521, 502, 326, 353, 469, 455, 190, 393, 453, 314, 480, 189, 77, 129, 439, 139, 441, 443, 351, 528, 182, 101, 501, 425, 126, 231, 445, 155, 432, 418, 95, 375, 376, 60, 271, 74, 11, 419, 488, 486, 54, 460, 321, 341, 174, 408, 131, 115, 107, 134, 448, 532, 292, 289, 320, 14, 323, 61, 481, 371, 151, 385, 325, 472, 44, 335, 431, 187, 51, 88, 105, 145, 215, 122, 162, 458, 52, 496, 277, 362, 374, 26, 211, 452, 130, 346, 10, 315, 459, 92, 531, 467, 309, 34, 281, 478, 477, 136, 519, 196, 240, 12, 288, 302, 119, 356, 503, 527, 22, 27, 55, 343, 490, 127, 444, 308, 354, 278, 497, 191, 294, 117, 1, 396, 125, 148, 285, 509, 208, 382, 297, 405, 245, 5, 330, 311, 133, 274, 275, 118, 463, 504, 39, 99, 442, 337, 169, 140, 104, 373, 221, 499, 413, 124, 510, 159, 465, 80, 276, 83, 329, 524, 255, 387, 259, 397, 491, 517, 23, 4, 230, 48, 349, 412, 142, 114, 487, 381, 164, 35, 67, 498, 73, 440, 108, 226, 96, 132, 144, 207, 235, 33, 69, 128, 236, 364, 198, 475, 173, 493, 150, 90, 515, 111, 68, 232, 340, 112, 526, 492, 512, 495, 429, 146, 336, 17, 350, 251, 7, 184, 76, 380, 359, 293, 19, 49, 345, 227, 212, 430, 89, 474, 279, 201, 398, 347, 273, 37, 185, 177, 102, 304, 295, 422, 94, 426, 514, 116, 183, 180, 494, 42, 305, 152, 390, 30, 247, 451, 32, 388, 331, 78, 424, 368, 394, 188, 306, 449, 8, 214, 120, 179, 280, 511, 409, 338, 153, 507, 370, 461, 217, 161, 483, 147, 242, 86, 417, 268, 71, 462, 420, 167, 513, 379, 307, 522, 435, 113, 296, 457, 525, 45, 529, 423, 427, 2, 438, 64, 316, 46, 40, 13, 516, 367, 233, 110, 318, 250, 283, 216, 186, 310, 237, 377, 365, 175, 479, 378, 66, 414, 473, 165, 210, 50, 348, 372, 363, 339, 20, 168, 284, 415, 505, 206, 53, 223, 434, 202, 123, 399, 400, 135, 269, 428, 219, 456, 28, 464, 267, 489, 98, 391, 195, 366, 300, 484, 533, 229, 213, 149, 160, 256, 303, 530, 301, 29, 404, 344, 401, 220, 287, 9, 407, 170, 450, 523, 249, 72, 410, 3, 21, 200, 260});
}

public static void find(int[] numbers){
    int sum = 0;
    int duplicate = -1;

    for (int i = 0; i < numbers.length; i++) {
        sum += numbers[i];

        if(duplicate == -1) {
            for (int j = i + 1; j < numbers.length; j++) {
                if(numbers[i] == numbers[j]){
                    duplicate = numbers[i];
                }
            }
        }
    }

    int missing = triangle(numbers.length) - (sum - duplicate);

    System.out.println(duplicate + " " + missing);
}

public static int triangle(int amount) {
    return (int) ((Math.pow(amount, 2) + amount) / 2);
}

【讨论】:

    【解决方案4】:

    我会建议一个更好的方法来做到这一点。以下是您需要遵循的合乎逻辑的步骤。

    我用一个例子来解释

    例如:- 不正确的数组 => {20,30,40,40} 和正确的数组 => {20,30,40,60}

    1. 首先计算正确数组和不正确数组的总和。

    不正确的数组总和 => 130 和正确的数组 => 150

    1. 计算这两个数组的sum 之间的差异。

    差异将是-20(负)。

    1. 然后找到重复的Integer值。

    使用循环迭代找出得到RepeatedFrom 不正确数组的数字。所以重复编号将是40

    1. 现在Substract 这个重复数字与您发现的差异(在两个总和之间)

    (-20)-(-40) = -60你得到了你丢失的号码。

    1. 最后你会得到你的负数。这是更有效的方法。

    注意 :- 如果您在嵌套循环中的(n*n) 中遍历一个不正确的数组(n) 并在嵌套循环中再次在嵌套循环中遍历正确的数组(n)(n*n) 所以,总计将是(n*n*n*n)。它实际上非常忙碌。在我给出的解决方案中,最大可达((n*n)+n+n)。所以绝对

    【讨论】:

      猜你喜欢
      • 2014-11-01
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      • 2014-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-20
      相关资源
      最近更新 更多