1. 程式人生 > >給定一個數組,找出陣列缺少的最小的正整數

給定一個數組,找出陣列缺少的最小的正整數

題目使這樣的:請設計一個高效演算法,查詢陣列中未出現的最小正整數。

給定一個整數陣列A,請返回陣列中未出現的最小正整數。

測試樣例:

[-1,2,3,4]

返回1

一看到這個題目我想到的是用另外的一個數組B,長度為A的長度+1,來儲存遍歷陣列A的數的值。 if(A[i] == i+1)  B[i+1] = A[i]。然後遍歷陣列B,出現空缺的地方即是最小未出現的正整數。但是假如要求額外空間複雜度為O(1),那就沒辦法了。有的人會想到排序,但是排序最好需要O(nlog2n)的時間複雜度。如果要求時間複雜度為O(n),並且空間複雜度為O(1),那麼要怎麼做呢?這方法是我在牛客網上看到的。聽完之後,感覺特別不可思議,實在是太厲害了。在我的理解裡,這是一種正向和逆向結合的思想。從前往後和從後往前不停地進行,理想情況和實際情況實時地更新,最後的臨界點必然是兩者相等。

在這個演算法裡,有兩個額外變數。一個是match,初始值為0。用來標記從正整數1開始已經連續出現的正整數個數。比如說[3, 5, 2, 1, 6] 出現的連續正整數序列為{1 2 3 },所以match= 3;還有一個變數是maxMatch,初始值是整個陣列的長度,因為陣列在沒遍歷之前,無法得知其中的元素,所以看作是最理想的情況:裡面的數剛好是1到n。

說了兩個變數之後,便是演算法的部分了。

首先從第0位置開始,如果A[0]=match+1;那麼說明出現了下一個連續的正整數,所以match++;

如果A[0] != mach+1,那麼有幾種情況。

第一種情況是,A[0]<=match,那麼這個值是我們不需要的,因為match之前的正整數已經出現了。所以這時候剩下的數最多能使match的值達到maxMatch-1,因為這個無效的元素,需要佔用一個位置。同理如果A[0]>maxMatch,這個值也是不需要的,maxMatch-1;還有就是如果這個數在match和maxMatch的範圍之內,我們需要判斷這個數應該在的位置上,是否已經有了這個數。比如說A[0]=3,那麼我們只需要比較A[2]位置上是否是3,如果是那麼這個數也不是我們需要的,這是maxMatch-1;以上幾種情況都是遍歷的位置上的數是不需要的,那麼我們應該把後面的數調到這個位置上,進行重新搜尋。

還有一種情況就是 match+1<A[0]<=maxMatch,並且A[0]應該在的位置上的數不是A[0],那麼這個數就是我們可能需要的,所以把它放在它應該在的位置。比如說[3, 5, 2, 1, 6],3應該在的位置是2,A[2]上的數字是2,不等於3.所以3應該放在2的位置。這時我們應該交換兩個數的位置A[0] <=> A[2];

這樣一直搜尋下去,最終便是達到臨界點,然後結束搜尋。最終的結果便是match+1;

public static int firstMissingPosition(int[] nums) {
		 	if(null == nums){
	            throw new NullPointerException("輸入的陣列為空...");
	        }else if(0 == nums.length){
				return 1;
			}
	        
	        int match = 0;
		    int maxMatch = nums.length;
		    
		    while(match<maxMatch){
			    if(nums[match]==match+1){
			    	match++;
			    }else if(nums[match]<=match || nums[match]>maxMatch || nums[nums[match]-1] == nums[match]){
			    	maxMatch--;
			    	nums[match] = nums[maxMatch];
			    }else {
					int temp = nums[match];
					nums[match] = nums[temp-1];
					nums[temp-1] = temp;
				}
		    }
		   return match+1;
	    }

程式碼量很少,但是思路真的是很精妙。不得不為之讚歎!

相關推薦

給定個數陣列缺少整數

題目使這樣的:請設計一個高效演算法,查詢陣列中未出現的最小正整數。 給定一個整數陣列A,請返回陣列中未出現的最小正整數。 測試樣例: [-1,2,3,4] 返回1 一看到這個題目我想到的是用另外的一個數組B,長度為A的長度+1,來儲存遍歷陣列A的數的值。 if(A[i]

給定個數這個和大的連續子陣列的和

將這個連續子陣列分為兩部分,一個是字首,一個是後一個元素,要使這個連續子陣列最大,那麼它的字首肯定不能為負,不然這個字首對即將加上的值就無意義,用一個max記錄最大值,每次當前綴加上後一個元素的時候判斷和是否大於max,大於則更新max,再判斷和是否小於0,小於0則將字首更

給定個數其中出現奇數次的元素

package com.yzcl.test; public class JiShu { public static void main(String[] args) { //給定一個含有n個元素的整型陣列a,例如{1,1,2,4,3,3,1},找出其中出現奇數次的元素,並列印,輸出:1,

給定個數陣列元素的排列和組合——Java實現

1. 思路 組合數C(n,m)和全排列A(n,n)可以通過遞迴的方式,直接實現。 而A(n,m)則可以通過組合數和全排列間接求出A(n,m)=C(n,m)*A(m,m),即對得到的組合數中的每個元素進行全排列 2. Java實現 package com.zfy.test

給定個數按序排列陣列若干個數使得這若干個數字的和與M最為接近(揹包問題)

思路:對於陣列中的每一個數,觀察它們取或不取對最後結果的影響。並且記錄下若干數字的和與M的差的絕對值最小時所取到的若干數字。 /*  * 微軟100, 9月28題, 輸入和接近M  * sum 即為M值  * num排序的陣列  * len陣列長度  * vec所取到若干數

給定個數其中只有個數出現別的數都出現3次個數(go)

1.思路 用兩個數one=0、two=0分別記錄bits位上1出現的次數,如果一個數出現一次,則one等於這個數,two=0;  如果一個數出現兩次,則two等於這個數, one等於0;如果一個數出現第三次,則one = 0, two = 0 ,three等於這個數。 我們以陣

給定個數其中只有個數出現別的數都出現3次個數

題目描述 給定一個數組,其中只有一個數x出現一次,別的數都出現3次,找出這個數x。(線性時間複雜度) 思路 這個用異或不可以。 可以設定一個長度為32的int陣列。統計每位上出現1的次數,如果次數能被3整除,說明x該位上為0,否則為1 java程式碼實

給定個數陣列中有有負連續陣列中和值大的數(陣列長度大於等於1)

刷牛牛客遇到的題,想給出完整而又簡潔的function(python解答,但是關鍵是思想,語言不是問題啦)1.給定一個數組,陣列中有正有負,求出連續(全部都是正的時候,所有值累加就是最大值)(全部為負的時候,max(array)就是我們想要的)# -*- coding:utf

給定個數陣列中有負數所有字陣列中和值大的值。

/**當我們加上一個正數時,和會增加;當我們加上一個負數時,和會減少。如果當前得到的和是個負數,那麼這個和在接下來的累加中應該拋棄並重新清零, 不然的話這個負數將會減少接下來的和 */ public static int maxSum(int[] a) { int

一個輸入的陣列中長度為101陣列範圍[1,100]存在個數重複重複的數

  /********************************************* *函式功能: 一個輸入的陣列中長度為101,陣列範圍[1,100],存在一個數重複,找出重複的數 *引數說明 * 輸入: [1,2,4,5,6,...,39,39,40,41,

有自己的程式碼--題目:給定一個數組,裡面全是正整數。數字大小表示這多可以向後移動幾個節點。總是從陣列第一個元素開始移動。問如何移動可以以最少步數移動到最後一個節點。

原文:https://yq.aliyun.com/articles/547799 描述: 題目:給定一個數組,裡面全是正整數。數字大小表示這一步最多可以向後移動幾個節點。總是從陣列第一個元素開始移動。問如何移動,可以以最少步數移動到最後一個節點。 例如:[3,4,2

給定個數根據陣列名求陣列的長度

題目:給定一個數組名字,如何根據陣列名求陣列的長度? 本題來自於一個同學筆試題,筆試中是實現一個氣泡排序,但是排序的引數只有一個數組名,沒有陣列中元素的個數;void bubbleSort(int a

給定個數返回大子陣列的累加和並且返回該子陣列

給定一個數組Arr,返回子陣列的最大累加和 例如 arr[] = {1,-2,3,5,-2,6,-1};所有子陣列中,[3,5,-2,6] 可以累加出最大和12 函式在設計的時候,應該考慮傳入的陣列Arr,同時要有一個傳出陣列,返回值會最大累加和,為整數 以下是程式碼

面試題:給定個數陣列中只包含0和1。請找到一個長的子序列其中0和1的數量是相同的

這個題目,看起來比較簡單,一些同學可能認為題目的描述符合動態規劃的特徵,然後就開始用動態規劃解,努力找狀態轉移方程。這些同學的感覺,是很正確的。但,找狀態轉移方程,我們要對原來的陣列進行變換一下。 原來是0和1的串,我們將0都換為-1。這樣題目目標就變成,找到一個最長的子串,子串數字和是0。設原陣列為A

題目三:給定個數值可以為、負和0請返回累加和為給定值k的長子陣列長度。

import java.util.HashMap; /** * * 2、給定一個數組,值可以為正、負和0,請返回累加和為給定值k的最長子陣列長度。 * 咱們可以反推,比如:1- 100,陣列和為1000. * 要求最長和為300的子陣列,我可以反著求第一

題目四:給定個數值可以為、負和0請返回累加和小於等於k的長子陣列長度。 時間複雜度:O(n)

import java.util.HashMap; /** * * 3、給定一個數組,值可以為正、負和0,請返回累加和小於等於k的最長子陣列長度。 時間複雜度:O(n) * * 這裡需要分為兩步,第一步是獲取,以每個位置開頭最小和的長度。第二步,從0到N逐

給定個數它的第 i 個元素是給定股票第 i 天的價格。 如果你多只允許完成筆交易(即買入和賣支股票)設計一個算法來計算你所能獲取的大利潤。

pan stat 給定 arr 註意 turn 大於 交易 nbsp 給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。 如果你最多只允許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。 註意你不能在買入股票前賣出股票。 示例 1

JS寫一個方法傳入個數返回該陣列的層深

現在我們有一個多維陣列,我們想得到該陣列的層深,即最大維度 如:var arr = [1, [4,[5,6,[7]]], [2,3]] = 0;返回4;那麼我們該怎麼做呢? 核心思想:遞迴,迴圈遍歷 // 這裡傳入兩個引數 // 引數一為陣列 // 引數二為初始陣列的層深 function fo(

隨機數生成個數對該陣列檢索

生成一個含100個隨機數的陣列,對其進行檢索,這裡以二分檢索為例。 import java.util.Random; import java.util.Scanner; //引入隨機數的二分檢索 public class RandomErfen { public static voi

給定個數請倒序輸出每個數

題目描述: 給定一個數組, int[] abc = { 20, 90, 48, 92}; 請倒序輸出每一個數。 即,輸出 92 48 90 20 c #include<stdio.h> int main() {     int a[4]={20,90,48