javascript - 如何在数组中找到第一个重复项?
问题描述
您好正在尝试在数组中查找重复项。
这是我的问题
给定一个 1 到 n 之间的 n + 1 个整数的只读数组,找到一个在线性时间内重复使用小于 O(n) 空间并顺序遍历流 O(1) 次的数字。
- 输入 :
[3 4 1 4 1]
- 输出:1
如果有多个可能的答案(如上面的示例),则输出任何一个。
如果没有重复,输出-1
let repeatedNumber = function(A) {
let result = -1
for (let i = 0; i < A.length; i++) {
if (A[Math.abs(A[i]) - 1] < 0) {
result = i
break
} else {
A[Math.abs(A[i]) - 1] = -A[Math.abs(A[i]) - 1]
}
}
return ++result
}
// working fine..!!
console.log(repeatedNumber([3, 4, 1, 4, 1]))
// output 4 is equal to expected output
// fail test case
console.log(repeatedNumber([247, 240, 303, 9, 304, 105, 44, 204, 291, 26, 242, 2, 358, 264, 176, 289, 196, 329, 189, 102, 45, 111, 115, 339, 74, 200, 34, 201, 215, 173, 107, 141, 71, 125, 6, 241, 275, 88, 91, 58, 171, 346, 219, 238, 246, 10, 118, 163, 287, 179, 123, 348, 283, 313, 226, 324, 203, 323, 28, 251, 69, 311, 330, 316, 320, 312, 50, 157, 342, 12, 253, 180, 112, 90, 16, 288, 213, 273, 57, 243, 42, 168, 55, 144, 131, 38, 317, 194, 355, 254, 202, 351, 62, 80, 134, 321, 31, 127, 232, 67, 22, 124, 271, 231, 162, 172, 52, 228, 87, 174, 307, 36, 148, 302, 198, 24, 338, 276, 327, 150, 110, 188, 309, 354, 190, 265, 3, 108, 218, 164, 145, 285, 99, 60, 286, 103, 119, 29, 75, 212, 290, 301, 151, 17, 147, 94, 138, 272, 279, 222, 315, 116, 262, 1, 334, 41, 54, 208, 139, 332, 89, 18, 233, 268, 7, 214, 20, 46, 326, 298, 101, 47, 236, 216, 359, 161, 350, 5, 49, 122, 345, 269, 73, 76, 221, 280, 322, 149, 318, 135, 234, 82, 120, 335, 98, 274, 182, 129, 106, 248, 64, 121, 258, 113, 349, 167, 192, 356, 51, 166, 77, 297, 39, 305, 260, 14, 63, 165, 85, 224, 19, 27, 177, 344, 33, 259, 292, 100, 43, 314, 170, 97, 4, 78, 310, 61, 328, 199, 255, 159, 185, 261, 229, 11, 295, 353, 186, 325, 79, 142, 223, 211, 152, 266, 48, 347, 21, 169, 65, 140, 83, 156, 340, 56, 220, 130, 117, 143, 277, 235, 59, 205, 153, 352, 300, 114, 84, 183, 333, 230, 197, 336, 244, 195, 37, 23, 206, 86, 15, 187, 181, 308, 109, 293, 128, 66, 270, 209, 158, 32, 25, 227, 191, 35, 40, 13, 175, 146, 299, 207, 217, 281, 30, 357, 184, 133, 245, 284, 343, 53, 210, 306, 136, 132, 239, 155, 73, 193, 278, 257, 126, 331, 294, 250, 252, 263, 92, 267, 282, 72, 95, 337, 154, 319, 341, 70, 81, 68, 160, 8, 249, 96, 104, 137, 256, 93, 178, 296, 225, 237]))
// output 327 is equal to expected output 73
我的方法
我正在制作索引negative
,以便在迭代索引时positive index is my dublicate item
解决方案
我认为使用一个跟踪迄今为止找到的元素的 Set 或对象会简单得多。当找到重复元素时,返回它:
let repeatedNumber = function(A) {
const set = new Set();
for (const item of A) {
if (set.has(item)) return item;
set.add(item);
}
return -1;
}
console.log(repeatedNumber([3, 4, 1, 4, 1]))
console.log(repeatedNumber([247, 240, 303, 9, 304, 105, 44, 204, 291, 26, 242, 2, 358, 264, 176, 289, 196, 329, 189, 102, 45, 111, 115, 339, 74, 200, 34, 201, 215, 173, 107, 141, 71, 125, 6, 241, 275, 88, 91, 58, 171, 346, 219, 238, 246, 10, 118, 163, 287, 179, 123, 348, 283, 313, 226, 324, 203, 323, 28, 251, 69, 311, 330, 316, 320, 312, 50, 157, 342, 12, 253, 180, 112, 90, 16, 288, 213, 273, 57, 243, 42, 168, 55, 144, 131, 38, 317, 194, 355, 254, 202, 351, 62, 80, 134, 321, 31, 127, 232, 67, 22, 124, 271, 231, 162, 172, 52, 228, 87, 174, 307, 36, 148, 302, 198, 24, 338, 276, 327, 150, 110, 188, 309, 354, 190, 265, 3, 108, 218, 164, 145, 285, 99, 60, 286, 103, 119, 29, 75, 212, 290, 301, 151, 17, 147, 94, 138, 272, 279, 222, 315, 116, 262, 1, 334, 41, 54, 208, 139, 332, 89, 18, 233, 268, 7, 214, 20, 46, 326, 298, 101, 47, 236, 216, 359, 161, 350, 5, 49, 122, 345, 269, 73, 76, 221, 280, 322, 149, 318, 135, 234, 82, 120, 335, 98, 274, 182, 129, 106, 248, 64, 121, 258, 113, 349, 167, 192, 356, 51, 166, 77, 297, 39, 305, 260, 14, 63, 165, 85, 224, 19, 27, 177, 344, 33, 259, 292, 100, 43, 314, 170, 97, 4, 78, 310, 61, 328, 199, 255, 159, 185, 261, 229, 11, 295, 353, 186, 325, 79, 142, 223, 211, 152, 266, 48, 347, 21, 169, 65, 140, 83, 156, 340, 56, 220, 130, 117, 143, 277, 235, 59, 205, 153, 352, 300, 114, 84, 183, 333, 230, 197, 336, 244, 195, 37, 23, 206, 86, 15, 187, 181, 308, 109, 293, 128, 66, 270, 209, 158, 32, 25, 227, 191, 35, 40, 13, 175, 146, 299, 207, 217, 281, 30, 357, 184, 133, 245, 284, 343, 53, 210, 306, 136, 132, 239, 155, 73, 193, 278, 257, 126, 331, 294, 250, 252, 263, 92, 267, 282, 72, 95, 337, 154, 319, 341, 70, 81, 68, 160, 8, 249, 96, 104, 137, 256, 93, 178, 296, 225, 237]))
但这需要O(n)
空间,最坏的情况。
在只有一个重复的情况下,您可以总结从 1 到没有重复的序列的n
总期望值。对输入数组求和,它与预期和之间的差是重复数:
let repeatedNumber = function(arr) {
const expectedLen = arr.length - 1;
const expected = (expectedLen * (expectedLen + 1)) / 2;
return arr.reduce((a, b) => a + b) - expected;
}
console.log(repeatedNumber([3, 2, 1, 4, 1]));
console.log(repeatedNumber([1, 2, 3, 4, 5, 5, 6]));
如果可能有多个重复项,一种方法是将数组视为图形,其中数组的每个元素都是指向数组其他元素的指针。例如,如果第一个元素是 3,则它是指向数组索引 3 的指针。以这种方式看待它,找到一个重复元素涉及找到一个索引/数字,当它被视为一个图形时,它包含在一个循环中(如果遵循这些索引,最终会指向它们自己)。
有一些算法可以解决这个问题。其中之一是龟兔赛跑:
let repeatedNumber = function(A) {
let slow = A[0];
let fast = A[A[0]];
while (slow !== fast) {
slow = A[slow];
fast = A[A[fast]];
}
fast = 0;
while (fast !== slow) {
slow = A[slow]
fast = A[fast]
}
return slow;
}
console.log(repeatedNumber([3, 4, 1, 4, 1]))
console.log(repeatedNumber([247, 240, 303, 9, 304, 105, 44, 204, 291, 26, 242, 2, 358, 264, 176, 289, 196, 329, 189, 102, 45, 111, 115, 339, 74, 200, 34, 201, 215, 173, 107, 141, 71, 125, 6, 241, 275, 88, 91, 58, 171, 346, 219, 238, 246, 10, 118, 163, 287, 179, 123, 348, 283, 313, 226, 324, 203, 323, 28, 251, 69, 311, 330, 316, 320, 312, 50, 157, 342, 12, 253, 180, 112, 90, 16, 288, 213, 273, 57, 243, 42, 168, 55, 144, 131, 38, 317, 194, 355, 254, 202, 351, 62, 80, 134, 321, 31, 127, 232, 67, 22, 124, 271, 231, 162, 172, 52, 228, 87, 174, 307, 36, 148, 302, 198, 24, 338, 276, 327, 150, 110, 188, 309, 354, 190, 265, 3, 108, 218, 164, 145, 285, 99, 60, 286, 103, 119, 29, 75, 212, 290, 301, 151, 17, 147, 94, 138, 272, 279, 222, 315, 116, 262, 1, 334, 41, 54, 208, 139, 332, 89, 18, 233, 268, 7, 214, 20, 46, 326, 298, 101, 47, 236, 216, 359, 161, 350, 5, 49, 122, 345, 269, 73, 76, 221, 280, 322, 149, 318, 135, 234, 82, 120, 335, 98, 274, 182, 129, 106, 248, 64, 121, 258, 113, 349, 167, 192, 356, 51, 166, 77, 297, 39, 305, 260, 14, 63, 165, 85, 224, 19, 27, 177, 344, 33, 259, 292, 100, 43, 314, 170, 97, 4, 78, 310, 61, 328, 199, 255, 159, 185, 261, 229, 11, 295, 353, 186, 325, 79, 142, 223, 211, 152, 266, 48, 347, 21, 169, 65, 140, 83, 156, 340, 56, 220, 130, 117, 143, 277, 235, 59, 205, 153, 352, 300, 114, 84, 183, 333, 230, 197, 336, 244, 195, 37, 23, 206, 86, 15, 187, 181, 308, 109, 293, 128, 66, 270, 209, 158, 32, 25, 227, 191, 35, 40, 13, 175, 146, 299, 207, 217, 281, 30, 357, 184, 133, 245, 284, 343, 53, 210, 306, 136, 132, 239, 155, 73, 193, 278, 257, 126, 331, 294, 250, 252, 263, 92, 267, 282, 72, 95, 337, 154, 319, 341, 70, 81, 68, 160, 8, 249, 96, 104, 137, 256, 93, 178, 296, 225, 237]))
推荐阅读
- python - 由 pyinstaller 生成的 exe 引发“权限被拒绝”错误
- reactjs - 我的 redux dispatch 语句有什么问题?
- python - _tkinter.TclError:屏幕距离错误“.!startpage”
- r - 在平行坐标图中离散地选择我想要的变量/列,并设置它以便这个图例也显示实际值
- visual-studio - 使用内核和插件解决方案时的发布问题
- python-3.x - HackerRank 动态数组
- composer-php - “最小稳定性”键出现在包的 composer.json 中时有什么作用?
- c# - 仅当接口文件中未定义公开可见的类型或成员时才显示 CS1591
- python - TypeError: 'float' 类型的对象没有 len(): 在尝试从 Excel 表向某些地址发送电子邮件时得到这个
- asp.net - 如何在 Angular 中获取浏览器的用户凭据