题目:

Given an unsorted integer array, find the first missing positive integer.

For example,
Given [1,2,0] return 3,
and [3,4,-1,1] return 2.

Your algorithm should run in O(n) time and uses constant space.

链接:   http://leetcode.com/problems/first-missing-positive/

题解:

找到第一个missing positive,要求O(n)。首先就想到了像sort colors一样的swap方法。把invalid case都swap到array的后部,两次pass就可以找到first mission positive。

Time Complexity - O(n), Space Complexity - O(1)

public class Solution {
public int firstMissingPositive(int[] nums) {
if(nums == null || nums.length == 0)
return 1;
int lo = 0, hi = nums.length - 1; while(lo <= hi) {
if(nums[lo] <= 0 || nums[lo] > hi) //invalid case
swap(nums, lo, hi--);
else if (nums[lo] == lo + 1)
lo++;
else if(nums[lo] < lo + 1) // duplicates in lower index
swap(nums, lo, hi--);
else {
if(nums[lo] == nums[nums[lo] - 1]) // duplicates in high index
swap(nums, lo, hi--);
else
swap(nums, lo, nums[lo] - 1); // swap to correct position
}
} for(int i = 0; i < nums.length; i++)
if(nums[i] != i + 1)
return i + 1;
return nums.length + 1;
} private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}

更简洁的写法是

public class Solution {
public int firstMissingPositive(int[] nums) {
if(nums == null || nums.length == 0)
return 1; for(int i = 0; i < nums.length; i++) {
if(nums[i] > 0 && nums[i] < nums.length && nums[i] != nums[nums[i] - 1]) {
swap(nums, i, nums[i] - 1);
i--; // recheck newly swaped value at position i
}
} for(int i = 0; i < nums.length; i++)
if(nums[i] != i + 1)
return i + 1;
return nums.length + 1;
} private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}

二刷:

二刷依然写得比较复杂, reference里面有很多很简洁的写法,要加以学习。思路是利用排除法和双指针夹逼,使用类似于sort colors里面的swap()来在O(n)的时间和O(1)的space遍历数组,我们有一下几种case:

  1. 当 nums == null || nums.length == 0的时候,我们返回最小正整数 1
  2. 设定lo = 0, hi = nums.length - 1
  3. 当nums[lo] <= 0或者nums[lo] > hi的时候,这两种情况为invalid,我们肯定能在数组中找到更合适的元素,我们swap(nums, lo, hi),然后hi--
  4. 接下来,当nums[lo] = lo + 1的时候,这时候是valid condition,我们增加lo = lo + 1
  5. 假如nums[lo] < lo +1,经历过上面的条件以后,我们可以肯定nums[lo] - 1 >= 0并且nums[lo] - 1 < lo,说明我们之前已经处理过nums[lo] - 1这个index,并且找到了一个合理的值。那么现在我们可以判断出这里的nums[lo]是一个duplicate,我们执行 swap(nums, lo, hi--)把它移动到数组末尾去。这个条件说明在lo这个index出现了duplicate。
  6. 现在剩下的情况是我们的nums[lo] > lo + 1,并且nums[lo] < hi。这时候算是我们的一般情况,我们要把这个nums[lo]交换到他应该处于的为止,并且这个位置的index > lo而且index < hi。 因为在理想的情况下,我们的index与值的对应关系应该是i = nums[i] - 1,所以我们要尝试把nums[lo]换到nums[lo] - 1这个位置。但在这个时候我们需要进行一个判断, 就是假如 lo = 2, nums[lo] = 5, 假设nums[nums[lo] - 1] = nums[4]也等于5怎么办? 假如我们交换的话,那程序就会陷入死循环。这个时候我们判断出这里当前的nums[lo]其实也是一个duplicate,是higher index  ”nums[lo] - 1"这个位置的duplicate。所以我们依然执行swap(nums, lo, hi--),把这个数字交换到当前的尾部去。
  7. 最后的情况就是nums[lo] != nums[nums[lo] - 1], 我们可以放心大胆地执行swap(nums, lo, nums[lo] - 1),让循环去判断接下来的情况。
  8. 最后我们需要从头算一遍i从0到nums.length - 1, nums[i]是否等于 i + 1,假如不等,即可返回i+1,否则我们要返回nums.length + 1。

可以简化的地方有很多很多很多。希望三刷的时候能理清逻辑,大大简化。

Java:

Time Complexity - O(n), Space Complexity - O(1)

public class Solution {
public int firstMissingPositive(int[] nums) {
if (nums == null || nums.length == 0) {
return 1;
}
int lo = 0, hi = nums.length - 1;
while (lo <= hi) {
if(nums[lo] <= 0 || nums[lo] > hi) {
swap(nums, lo, hi--);
} else if (nums[lo] == lo + 1) {
lo++;
} else if (nums[lo] < lo + 1) {
swap(nums, lo, hi--);
} else if (nums[lo] == nums[nums[lo] - 1]) {
swap(nums, lo, hi--);
} else {
swap(nums, lo, nums[lo] - 1);
}
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return nums.length + 1;
} private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}

把很多条件都放在了一起,少了几行。 还可以设置一个index变量来避免第二次循环的查找,留给三刷了。

public class Solution {
public int firstMissingPositive(int[] nums) {
if (nums == null || nums.length == 0) {
return 1;
}
int lo = 0, hi = nums.length - 1;
while (lo <= hi) {
if (nums[lo] == lo + 1) {
lo++;
} else if(nums[lo] <= 0 || nums[lo] > hi || nums[lo] < lo + 1 || nums[lo] == nums[nums[lo] - 1]) {
swap(nums, lo, hi--);
} else {
swap(nums, lo, nums[lo] - 1);
}
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return nums.length + 1;
} private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}

题外话:

1/23/2016,现在我家已经彻底被大雪封住了。有生以来从来没见过这么大的雪,还在继续下着。我家的门在一个走廊里,整个走廊现在都是30厘米左右高的雪。出去走廊走到外面的话,雪都累积到了大腿根部。幸好之前屯了不少粮食,现在还可以在家里吃鸳鸯火锅(小肥羊辣汤/海底捞酸菜鱼汤)。 据说有20万户断电,希望大家都平安吧。

三刷:

用得二刷逻辑。

Java:

public class Solution {
public int firstMissingPositive(int[] nums) {
if (nums == null || nums.length == 0) return 1;
int lo = 0, hi = nums.length - 1;
while (lo <= hi) {
if (nums[lo] > hi || nums[lo] <= 0) swap(nums, lo, hi--);
else if (nums[lo] == lo + 1) lo++;
else if (nums[lo] < lo + 1) swap(nums, lo, hi--);
else if (nums[lo] == nums[nums[lo] - 1]) swap(nums, lo, hi--);
else swap(nums, lo, nums[lo] - 1);
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i + 1) return i + 1;
}
return nums.length + 1;
} private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
class Solution {
public int firstMissingPositive(int[] nums) {
if (nums == null || nums.length == 0) return 1; for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0 && nums[i] < nums.length && nums[i] != nums[nums[i] - 1]) {
swap(nums, i, nums[i] - 1); // swap nums[i] out until nums[i] = i + 1 or nums[i] is invalid
i--;
}
} for (int i = 0; i < nums.length; i++) if (nums[i] != i + 1) return i + 1;
return nums.length + 1;
} private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}

Reference:

https://leetcode.com/discuss/20385/concise-o-n-solution

https://leetcode.com/discuss/32761/clear-java-solution

https://leetcode.com/discuss/60525/100%25-fast-elegant-java-index-based-solution-with-explanation

https://leetcode.com/discuss/28531/o-1-space-java-solution

https://leetcode.com/discuss/24013/my-short-c-solution-o-1-space-and-o-n-time

41. First Missing Positive的更多相关文章

  1. LeetCode - 41. First Missing Positive

    41. First Missing Positive Problem's Link ---------------------------------------------------------- ...

  2. [Leetcode][Python]41: First Missing Positive

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 41: First Missing Positivehttps://oj.le ...

  3. [array] leetcode - 41. First Missing Positive - Hard

    leetcode - 41. First Missing Positive - Hard descrition Given an unsorted integer array, find the fi ...

  4. LeetCode题解41.First Missing Positive

    41. First Missing Positive Given an unsorted integer array, find the first missing positive integer. ...

  5. 刷题41. First Missing Positive

    一.题目说明 题目是41. First Missing Positive,求一个未排序队列中缺失的最小正整数.时间复杂度要求是O(n).难度是Hard,确实难. 二.我的解答 不考虑时间复杂度,首先对 ...

  6. [LeetCode] 41. First Missing Positive 首个缺失的正数

    Given an unsorted integer array, find the smallest missing positive integer. Example 1: Input: [1,2, ...

  7. leetcode 41 First Missing Positive ---java

    Given an unsorted integer array, find the first missing positive integer. For example,Given [1,2,0]  ...

  8. Java [Leetcode 41]First Missing Positive

    题目描述: Given an unsorted integer array, find the first missing positive integer. For example,Given [1 ...

  9. leetcode problem 41 -- First Missing Positive

    Given an unsorted integer array, find the first missing positive integer. For example,Given [1,2,0]  ...

随机推荐

  1. Mvc中把list从View传入Controller

    public class User { public string Name { get; set; } public bool IsChecked { get;set;} public int Ag ...

  2. dotNet中初始化器的使用

    dotNet中初始化器的使用 2013年12月7日 13:27 有两类初始化器: 对象初始化器和集合初始化器 比如现在有一个User类: Public   class User { public in ...

  3. Python原始套接字编程

    在实验中需要自己构造单独的HTTP数据报文,而使用SOCK_STREAM进行发送数据包,需要进行完整的TCP交互. 因此想使用原始套接字进行编程,直接构造数据包,并在IP层进行发送,即采用SOCK_R ...

  4. 从Keil 4升级到Keil 5的工程,想返回来用Keil 4打开

    情景描述: 笔者电脑程序Keil 4升级到Keil 5,相应地,原来项目上的工程也在第一次用Keil 5打开的时候进行了升级.之后,由于客户需要开发资料,其版本为Keil 4,我尝试着用Keil 4打 ...

  5. SQL日语词汇

    データベース 数据库 DATABASE インスタンス (数据库)实例 INSTANCE ユーザー 用戶 USER ログイン・ログアウト ログオン・ログオフ 登录 LOGIN/LOGOUT LOGNO/ ...

  6. Java异常的深入研究与分析

    前言 本文是异常内容的集大成者,力求全面,深入的异常知识研究与分析.本文由金丝燕网独家撰写,参考众多网上资源,经过内容辨别取舍,文字格式校验等步骤编辑而成,以飨读者.对于本文的内容,建议小白需要多多思 ...

  7. 屏蔽ios7中某个页面的默认手势滑回返回

    - (void)viewWillDisappear:(BOOL)animated {[super viewWillDisappear:YES];self.navigationController.in ...

  8. Windows 10 响应式设计和设备友好的开发

    使用Effective pixels有效像素设计UI 什么是缩放像素和Effective有效像素: 当你的应用程序运行在Windows的设备,系统用一个算法控制的规范,字体,和其他UI元素显示在屏幕上 ...

  9. android 中使用回调方法(适用于自定义view传值到activity、adapter传值到activity)

    如图所示: 每当listview中有选中的操作时都需要发消息给activity,用来实时改变真实需要支付的剩余金额. 代码暂不公开啦!公司项目!

  10. android开发 java与c# 兼容AES加密

    由于android客户端采用的是AES加密,服务器用的是asp.net(c#),所以就造成了不一致的加密与解密问题,下面就贴出代码,已经试验过. using System; using System. ...