从未排序的数组中找到最小的正整数,精装版

时间:2018-07-26 10:20:21

标签: algorithm

经典问题

经典的问题陈述是:给定未排序的整数数组A,请找到A中不存在的最小正整数。

[3, 2, 1, 6, 5] -> 4
[2, 3, 4, 5] -> 1
[1, 2, 3, 4] -> 5

在经典的问题陈述中,您只能得到一个数组,并且可以找到有关此问题的许多解决方案和资源,hereherehere

硬版

在我的问题中,为您提供了两个数组,分别为AB。构造长度为N的数组C,其“最小丢失整数”可能最大N必须为C[i]A[i]

B[i]

如何用A = [1, 2, 4, 3], B = [1, 3, 2, 3] =-> C = [1, 2, 4, 3] answer = 5 A = [4, 2, 1, 6, 5], B = [3, 2, 1, 7, 7] =-> C = [3, 2, 1, 6, 5] answer = 4 A = [2, 3], B = [4, 5] =-> C = [2, 5] answer = 1 最坏的时间和空间复杂性来解决此问题?

假设:

O(N)

4 个答案:

答案 0 :(得分:2)

此算法可对数字范围O(n)中的数字加上处理输入的时间进行[0..n+2]算术运算。


  • 将所有不在[1..n]范围内的数字替换为n+2。这不会改变结果。
  • 使用标记为1, 2, 3, ..., n-1, n, n+2的节点构造一个图,并且对于所有0 <= i < n,在节点A[i]B[i]之间存在一条边(假定索引为0的数组)。因此该图具有n+1个节点和n个边。

现在,问题等同于找到一种方式来确定边的方向,以使最大度数为0的最小顶点成为可能。


  • 在图中找到连接的组件。
  • 对于每个具有v个顶点和e边的连接组件,e >= v-1

    • 如果e == v-1是一棵树。定向边缘的所有方法都将导致顶点的度数为0,并且可以证明对于树中的所有顶点,都存在一种定向边缘的方法,使其成为唯一度为0的顶点。

      方法:

        

      使树在该顶点处扎根,然后使每条边从父级直接指向子级。

      当然,最好(贪婪地)选择度数为0的顶点作为具有最高编号的顶点。

    • 如果e >= v,则所连接的组件内部存在电路。然后,可以对边缘进行定向,以使所有顶点的度数都非零。

      证明(以及构造边缘方向的方法)留给读者。

答案 1 :(得分:1)

如果您遍历数组并构建图,则在A或B中遇到的每个唯一整数都将成为一个顶点,并且每对整数A [i]和B [i]都会在两个顶点之间创建边,然后该图最多具有2×N个顶点,因此该图所占用的空间与N成线性关系。

然后,对于图形中的每个边,我们将决定其方向,即,它连接的两个整数中的哪个将在数组C中使用。最后,我们将再次遍历数组,对于每对整数,我们查看图中的相应边以了解要使用哪个整数。

我认为,确定图中方向的操作都可以在线性时间内完成(如果我错了,请纠正我),所以整个算法应该具有O(N)的时间和空间复杂度。

确定图中边缘方向的规则如下:

  • 图中未连接的部分分别进行单独处理。
  • 如果(子)图的边缘比顶点少(即,它的树结构没有循环),则必须牺牲最大的整数:将边缘指向远离该顶点的方向,并沿该方向传播其余的顶点。
  • 如果(子)图的边比顶点多(即,它包含至少一个循环,可以是两个顶点由多个边连接),则找到任意循环,并为其边指定相同的方向(顺时针方向均可)或逆时针);然后将方向传播到其他顶点。

遍历数组并查找图形中的相应边时,请在两个顶点多重连接时标记您已经使用的整数,以便第二次使用另一个整数。之后,您可以选择其中一个。

示例:

A = [1,6,2,9,7,2,5,3,4,10]
B = [5,8,3,2,9,7,1,2,8,3]

图:

1===5   6---8---4   9---2===3---10
                    |   |
                    --7--

我们找到循环[1> 5> 1]和[9> 2> 7> 9],以及非循环子图中的最高整数8。

有向图:

1<=>5   6<--8-->4   9-->2<=>3-->10
                    ^   |
                    |-7<-

结果:

C = [1,6,2,2,9,7,5,3,4,10]

第一个丢失的整数是8,因为我们必须牺牲它以保存[6,8,4]子图中的4和6。

答案 2 :(得分:1)

请检查此代码段,我已经用Java 8编写了

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


public class Run {
    private int solution(int[] A) {

        List<Integer> positiveIntegerList = Arrays.stream(A).distinct().filter(e -> e > 0).boxed().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
        final int i = 1;

        if (!positiveIntegerList.isEmpty()) {
            final int missingMax = positiveIntegerList.get(positiveIntegerList.size() - i) + i;
            List<Integer> range = IntStream.rangeClosed(i, positiveIntegerList.get(positiveIntegerList.size() - i))
                    .boxed().collect(Collectors.toList());

            AtomicInteger index = new AtomicInteger();
            return range.stream().filter(e -> !e.equals(positiveIntegerList.get(index.getAndIncrement()))).findFirst().
                    orElse(missingMax);
        } else {
            return i;
        }
    }


    public static void main(String[] args) {
        Run run = new Run();
        int[] intArray = new int[]{1, 3, 6, 4, 1, 2};
        System.out.println(run.solution(intArray));
    }
}

答案 3 :(得分:0)

我已经尝试了在Python3中解决此问题的方法。欢迎提出建议和反馈。谢谢。

  1. 从列表中删除负值
  2. 将0插入列表
  3. 使用排序和设置功能排序并从列表中删除重复项
  4. 使用枚举器创建索引和值。
  5. 比较索引和从(0,0)开始的值。如果索引和值不匹配,则下一个值为最小的正数。

-

from typing import List

class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        #Remove all the negative values from the list
        positive_list = [i for i in nums if i > 0]

        #Appending Zero to list. In case of no postive values in the list.
        positive_list.append(0)

        #Sort and remove duplicates from the list using Sorted and set function
        sorted_postive_list = sorted(set(positive_list))

        #starting with (index, value) --> (0,0), Compare index and value, and if they don't match then next value should be the smallest positive number
        return next((a for a, b in enumerate(sorted_postive_list, sorted_postive_list[0]) if a != b), sorted_postive_list[-1]+1)

if __name__ == "__main__":
    num = [1,2,3,0]
    a = Solution()
    print(a.firstMissingPositive(num))