Submission Details [leetcode] ---- inplace 线性时间 的两种思路

两种思路都利用了输入的数组A,若A中存在i,则给A[i]作为标记。

因为A中的n个元素存在>n和<=0的,所以第一个缺失的正整数一定在[1-n+1]之间。

第一种思路是将标记设为一个特定的数。因为改变数值会影响该位置原来存的值,所以需要在一个循环里依次处理所有“原来的值”。

例如数组为{2,3,4,1}。对第一个数2,我们将位置(2-1)=1标记为-MAX_INT,数组变为{2,-MAX_INT,4,1},丢失了3,所以应记录下数组原来的值,并继续将位置(3-1)=2标记为-MAX_INT。。。

int firstMissingPositive(int A[], int n) {
        for (int i = 0; i < n; i++)
        {
            int k = A[i];
            while (k > 0 && k <= n)
            {
                int temp = A[k-1];
                A[k-1] = - INT_MAX;
                k = temp;
            }
        }
        for (int i = 0; i < n; i++)
            if (A[i] != -INT_MAX)
                return i + 1;
        return n + 1;
    }

第二种思路,我们标记时可以不用改变数值,所以可以取消掉for里面的while循环。

如果不改变数值,我们能改变什么那?我们可以改变符号。这种思路里,数组中一开始存在的负数会对最终结果产生影响,所以我们做一个预处理----将所有负数变成一个大于n的数----INT_MAX。

int firstMissingPositive(int A[], int n) {
        for (int i = 0; i < n; i++)
        {
            if (A[i] <= 0) A[i] = INT_MAX;
        }
        for (int i = 0; i < n; i++)
        {
            int k = abs(A[i]);
            if (k <= n)
                A[k-1] = - abs(A[k-1]);
        }
        for (int i = 0; i < n; i++)
            if (A[i] > 0)
                return i + 1;
        return n + 1;
    }

两种方法的时间复杂度都是O(n),准确的说,是最坏的情况下都会遍历数组3遍。

时间: 2024-12-20 18:12:41

Submission Details [leetcode] ---- inplace 线性时间 的两种思路的相关文章

Letter Combinations of a Phone Number [leetcode]谈谈循环解法的两种思路

本系列博文中有很多两种思路的,其实是因为第一遍刷题的时候有一个想法,第二遍刷题的时候已经忘掉之前的思路了,又有新的想法了. 同时大部分代码我也同时PO到leetcode的对应题目的问答中去了,所以如果你也查看问题讨论的话会发现有和我一模一样的代码,其实就是我PO的:) 书接正文,基于循环的两种思路如下: 第一种思路 比如"234"这个字符串,我可以先将0...1的所有排列找到-->{"a", "b", "c"} 再进一步

[LeetCode] Maximum Product Subarray的两种思路

Find the contiguous subarray within an array (containing at least one number) which has the largest product. For example, given the array [2,3,-2,4], the contiguous subarray [2,3] has the largest product = 6. 这题和之前的一题Maximum Subarray非常类似,一个是求最大和,而这个是

线性时间将两个有序链表合成一个有序链表(constant additional space)

description: given two sorted singly list, merge them into one using constant additional space algorithm: we will reference the two linked list as list1 and list2 for convenience, since list1 is sorted,just find the right position for each element in

点击页面div弹窗以外隐藏的两种思路

在本文为大家介绍两种思路实现点击页面其它地方隐藏该div,第一种是对document的click事件绑定事件处理程序.. 第一种思路分两步 第一步:对document的click事件绑定事件处理程序,使其隐藏该div 第二步:对div的click事件绑定事件处理程序,阻止事件冒泡,防止其冒泡到document,而调用document的onclick方法隐藏了该div. <script type="text/javascript"> function stopPropagat

[Unity3d][NGUI]两种思路解决AssetBundle的依赖关系.

接上文. 使用上文中的AssetBundle打包方式生成的文件包括了依赖关系中的文件. 一般的使用中并不会发现什么问题. 可是当配合NGUI的时候,使用dynamicFont时打包AssetBundle会将每一个组件使用的dynamicFont都分开打包进去. 导出函数请參考:导出资源 导出资源包时出现的问题: 如图: 在解决依赖关系上我使用过2种方案: 第一种是使用BuildPipeline中的PushAssetDependencies和PopAssetDependencies方法来解决依赖关

二元查找树的翻转(镜像)的两种思路

问题描述: 输入一颗二元查找树,将该树转换为它的镜像, 即在转换后的二元查找树中,左子树的结点都大于右子树的结点. 算法: 测试用例: 10 /             \ 5               11 /        \ 3            7 /     \         /   \ 2       4     6      9 /                       / 1                       8 算法: 有两种思路: ①递归.对树翻转,只

Jump Game II (leetcode) DP的两种思路

第一种思路是: dp(i):到位置i所需要的最少步数 dp(i)一定是递增的,所以从j=A[i]开始(从最远的位置开始),更新数组直到dp(j+i) <= dp(i) + 1为止 如果去掉,会TLE int jump(int A[], int n) { int* dp = new int[n];//dp[i]到i所需的最小步数 memset(dp, 0x3f, sizeof(int) * n); dp[0] = 0; for (int i = 0; i < n; i++) { for (int

Reorder List [leetcode] 的两种思路

第一种思路是用一个vector存所有的Node* 之后再用两个指针将链表拼接出来 void reorderList(ListNode *head) { vector<ListNode*> content; ListNode * cur = head; while (cur) { content.push_back(cur); cur = cur->next; } int size = content.size(); cur = NULL; for (int i = 0; i <=

详谈排序算法之插入类排序(两种思路实现希尔排序)

1. 排序( sorting) 的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列.其确切的定义为: 假设有n个数据元素的序列{R1 , R2 , - , Rn},其相应关键字的序列是{K1 , K2 , - , Kn} ,通过排序要求找出下标 1 , 2 , - , n的一种排列p1 , p2 , - , pn,使得相应关键字满足如下的非递减(或非递增)关系Kp1 ≤ Kp2 ≤ - ≤ Kpn这样,就得到一个按关键字有序的纪录序列{ Rp1 , Rp2 , - , Rpn }