随笔 - 40  文章 - 0  评论 - 48  阅读 - 13万

LeetCode 笔记系列11 First Missing Positive [为什么我们需要insight]

题目: 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.

为什么这道题值得纪念呢? 因为它教育我们看问题看本质。

要看出问题本质,首先要深刻理解问题本身是在说啥。。。(越来越像学习某某core的讲话了)

在一个无序的整数数组中,找出第一个没有的正数。什么意思呢?这么想,所有正数是1,2,3,4,5,....(把8倒过来). 找出最小的在这个数组中没有的数。而且人家要O(n),那说明你就没法用排序算法了。但是你肯定想到用hash是不是。一般来说,切题用hash都是没有办法的办法,不过人说了,“uses constant space“,hash都没法用了是不。

我遇到这样的题第一个本能的想法是用bit位移来做。这其实是有些讨巧的hash方法,相当于hash表的长度就只有一个整数大小。首先扫描数组,如果遇到正数i,就把该某个int值的i位置1。最后扫描那个int值,找出第一个0值。也是O(n)有木有。。。

代码是酱紫的。

解法一:

复制代码
 1 public static int firstMissingPositive(int[] A) {
 2             // Start typing your Java solution below
 3             // DO NOT write main() function
 4            int bits = 0;
 5            for(int i = 0; i < A.length; i++){
 6                if(A[i] > 0){
 7                    bits |= (1 << (A[i] - 1));
 8                }
 9            }
10            int idx = 0;
11            while(bits%2 != 0){
12                bits = (bits >> 1);
13                idx++;
14            }
15            return idx + 1;
16      }
View Code
复制代码

我觉得也符合条件呀,然后大集合就废了。超时超时。。。。

解法二:

我发现大牛们的有几个共同的特点。1. 比较快速地看问题本质;2. 可能切题很多,比较容易举一反三。

比如这个题,假设数组长度是n。那么第一个missing的正数肯定不会超过n啊混蛋。如果把所有正数都放在正确的位置上,数字1(如果有的话)在A[0], 数字2(如果有的话)在A[1],数字i + 1在A[i],那么我们只要扫描A,遇到第一个A[i]不等于i+1的,就知道这个missing的正数(i+1)了。大家可以用上面的例子仔细想想这个道理。但是怎么在O(n)时间内把数字i + 1(如果有的话)移动到A[i]呢?我估计大牛们肯定早就知道这个算法了。“范围内整数的线性排序”,我之前也在wiki上见过。就是把1-n的整数放置到长度为n的数组中,有序,in-place。

具体方法是,扫描数组A,如果当前的正数A[i]不在其该在的位置,那和A[A[i]-1]交换(这样交换过后A[i]-1的正数就in postion了。继续,直到i位置上的正数是正确的。然后继续下一个交换。

这样总能把所有正数in position。

差距,差距呀。。。

先上代码。

复制代码
 1 public static int firstMissingPositive2(int[] A){
 2         for(int i = 0; i < A.length; i++){
 3             if(A[i] > 0 && A[i] <= A.length){
 4                 if(A[i] != i + 1 && A[A[i] - 1] != A[i]){
 5                     int tmp = A[A[i] - 1];
 6                     A[A[i] - 1] = A[i];
 7                     A[i] = tmp;
 8                     i--;
 9                 }
10             }
11         }
12         
13         for(int i = 0; i < A.length; i++){
14             if(A[i] != i+1){
15                 return i+1;
16             }
17         }
18         return A.length + 1;
19      }
View Code
复制代码

这里在swap之前判断了两个条件,因为数组中并不一定包含所有的可以in-postion的正数。

总结:

1)还是题做得不够多;

2)下笔前分析透彻。

 

 

posted on   lichen782  阅读(1095)  评论(0编辑  收藏  举报
编辑推荐:
· 为什么构造函数需要尽可能的简单
· 探秘 MySQL 索引底层原理,解锁数据库优化的关键密码(下)
· 大模型 Token 究竟是啥:图解大模型Token
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· 继承的思维:从思维模式到架构设计的深度解析
阅读排行:
· 基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
· 由 MCP 官方推出的 C# SDK,使 .NET 应用程序、服务和库能够快速实现与 MCP 客户端
· 电商平台中订单未支付过期如何实现自动关单?
· 上周热点回顾(3.31-4.6)
· 用 .NET NativeAOT 构建完全 distroless 的静态链接应用
< 2025年4月 >
30 31 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 1 2 3
4 5 6 7 8 9 10

点击右上角即可分享
微信分享提示