具有2个唯一数字的最大连续子数组的长度

时间:2018-10-30 05:31:26

标签: algorithm vector data-structures

我有一个数字数组,我想算出两个重复的唯一数字组成的连续子数组的最大长度。

例如,[2、3、4、3、2、2、4]将返回3,因为[3、2、2]的长度为3。

[2, 4, 2, 5, 1, 5, 4, 2] would return 3.
[7, 8, 7, 8, 7] would return 5.

编辑:我考虑过一个O(n ^ 2)解决方案,其中我从数组中的每个值开始并进行迭代,直到看到第三个唯一值为止。

for item in array:
    iterate until third unique element
    if length of this iteration is greater than existing max, update the max length
return maxlength

但是,我认为这不是一个有效的解决方案。

3 个答案:

答案 0 :(得分:2)

可以完成O(n)。该代码在python3中。 ot分别是1和2。 m是最大值,c是当前计数变量。

a = [7, 8, 7, 8, 7]
m = -1
o = a[0]
t = a[1]
# in the beginning one and two are the first 2 numbers 
c = 0
index = 0
for i in a:
    if i == o or i == t:
        # if current element is either one or two current count is increased
        c += 1
    else:
        # if current element is neither one nor two then they are updated accordingly and max is updated
        o = a[index - 1]
        t = a[index]
        m = max(m, c)
        c = 2
    index += 1
m = max(m, c)

print(m)

答案 1 :(得分:0)

我们可以使用两个指针技术来解决O(n)运行时复杂性的问题。这两个指针,例如startPtrendPtr将表示数组中的范围。我们将以不超过2个唯一编号的方式维护此范围[startPtr, endPtr]。我们可以通过跟踪2个唯一编号的位置来做到这一点。我的C ++工具如下:

int main()
{
    int array[] = {1,2,3,3,2,3,2,3,2,2,2,1,3,4};
    int startPtr = 0;
    int endPtr = 0;

    // denotes the size of the array
    int size= sizeof(array)/sizeof(array[0]);

    // contain last position of unique number 1 in the range [startPtr, endPtr] 
    int uniqueNumPos1 = -1; // -1 value represents it is not set yet

    // contain last position of unique number 2 in the range [startPtr, endPtr]
    int uniqueNumPos2 = -1; // -1 value represents it is not set yet


    // contains length of maximum continuous subarray with 2 unique numbers
    int ans = 0;

    while(endPtr < size) {
        if(uniqueNumPos1 == -1 || array[endPtr] == array[uniqueNumPos1]) {
            uniqueNumPos1 = endPtr;
        }
        else {
            if(uniqueNumPos2 == -1 || array[endPtr] == array[uniqueNumPos2]) {
                uniqueNumPos2 = endPtr;
            }
            else {
                // for this new third unique number update startPtr with min(uniqueNumPos1, uniqueNumPos2) + 1
                // to ensure [startPtr, endPtr] does not contain more that two unique
                startPtr = min(uniqueNumPos1, uniqueNumPos2) + 1;

                // update uniqueNumPos1 and uniqueNumPos2
                uniqueNumPos1 = endPtr -1;
                uniqueNumPos2 = endPtr;
            }
        }

        // this conditon is to ensure the range contain exactly two unique number
        // if you are looking for the range containing less than or equal to two unique number, then you can omit this condition
        if (uniqueNumPos1 != -1 && uniqueNumPos2 !=-1) {
            ans = max( ans, endPtr - startPtr + 1);
        }

        endPtr++;
    }

    printf("%d\n", ans);
}

感谢 @MBo 指出错误。

答案 2 :(得分:0)

import java.util.Arrays;
import static java.lang.System.out;
class TestCase{
    int[] test;
    int answer;
    TestCase(int[] test,int answer){
        this.test = test;
        this.answer = answer;
    }
}
public class Solution {
    public static void main(String[] args) {
        TestCase[] tests = {
                            new TestCase(new int[]{2, 3, 4, 3, 2, 2, 4},3),
                            new TestCase(new int[]{2, 3, 3, 3, 3, 4, 3, 3, 2, 2, 4},7),
                            new TestCase(new int[]{1,2,3,3,4,2,3,2,3,2,2,2,1,3,4},7),
                            new TestCase(new int[]{2, 7, 8, 7, 8, 7},5),          
                            new TestCase(new int[]{-1,2,2,2,2,2,2,2,2,2,2,-1,-1,4},13),
                            new TestCase(new int[]{1,2,3,4,5,6,7,7},3),
                            new TestCase(new int[]{0,0,0,0,0},0),
                            new TestCase(new int[]{0,0,0,2,2,2,1,1,1,1},7),
                            new TestCase(new int[]{},0)
        };

        for(int i=0;i<tests.length;++i){
            int ans = maxContiguousArrayWith2UniqueElements(tests[i].test);
            out.println(Arrays.toString(tests[i].test));
            out.println("Expected: " + tests[i].answer);
            out.println("Returned: " + ans);
            out.println("Result: " + (tests[i].answer == ans ? "ok" : "not ok"));
            out.println();
        }         
    }

    private static int maxContiguousArrayWith2UniqueElements(int[] A){
        if(A == null || A.length <= 1) return 0;
        int max_subarray = 0;
        int first_number = A[0],second_number = A[0];
        int start_index = 0,same_element_run_length = 1;
        for(int i=1;i<A.length;++i){
            if(A[i] != A[i-1]){ 
                if(first_number == second_number){
                    second_number = A[i];
                }else{
                    if(A[i] != first_number && A[i] != second_number){
                        max_subarray = Math.max(max_subarray,i - start_index); 
                        start_index = i - same_element_run_length;
                        first_number  = A[i-1];
                        second_number = A[i];
                    }
                }
                same_element_run_length = 1;
            }else{
                same_element_run_length++;
            }
        }

        return first_number == second_number ? max_subarray : Math.max(max_subarray,A.length - start_index);
    }
}

输出:

[2, 3, 4, 3, 2, 2, 4]
Expected: 3
Returned: 3
Result: ok

[2, 3, 3, 3, 3, 4, 3, 3, 2, 2, 4]
Expected: 7
Returned: 7
Result: ok

[1, 2, 3, 3, 4, 2, 3, 2, 3, 2, 2, 2, 1, 3, 4]
Expected: 7
Returned: 7
Result: ok

[2, 7, 8, 7, 8, 7]
Expected: 5
Returned: 5
Result: ok

[-1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, 4]
Expected: 13
Returned: 13
Result: ok

[1, 2, 3, 4, 5, 6, 7, 7]
Expected: 3
Returned: 3
Result: ok

[0, 0, 0, 0, 0]
Expected: 0
Returned: 0
Result: ok

[0, 0, 0, 2, 2, 2, 1, 1, 1, 1]
Expected: 7
Returned: 7
Result: ok

[]
Expected: 0
Returned: 0
Result: ok

算法:

  • 因此,我们维护2个变量 first_number second_number ,它们将保存这两个唯一数字。
  • 您知道,为了获得具有2个唯一元素的最大子数组长度,我们必须考虑许多可能的子数组。因此,我们需要一个指针变量,它将指向子数组的开始。在此,该指针为 start_index
  • 当我们找到不等于 first_number second_number 第三数字时,任何子数组都会中断。因此,现在,我们通过执行 i-start_index 来计算先前的子数组长度(具有这2个唯一元素)。
  • 这个问题的棘手部分是如何获取下一个子数组的 start_index
  • 如果您仔细观察,先前子数组的 second_number 会变成当前子数组的 first_number ,而我们刚才遇到的 second 会变成 second_number 这个当前子数组。
  • 因此,计算此 first_number 开始时间的一种方法是向后运行while循环以获得该 start_index 。但是,如果要考虑的子数组很多,它将使算法 O(n ^ 2)
  • 因此,我们维护一个名为 same_element_run_length 的变量,该变量仅跟踪数字重复的次数的长度或频率,并在中断时对其进行更新。因此,在遇到第三数字后,下一个子数组 start_index 将变为 start_index = i-same_element_run_length
  • 完成的其余操作是不言自明的。
  • 时间复杂度: O(n),空间复杂度: O(1)