1. 程式人生 > >尋找陣列中重複的數字

尋找陣列中重複的數字

引言

原題來自劍指offer第二版面試題三

題目:

在一個長度為n的數組裡的所有數字都在0~n-1範圍內。陣列中某些數字是重複的。但是不知道有幾個數字重複了,也不知道每個數字重複了幾次。請找出陣列中任意一個重複的數字。例如,如果輸入長度為7的陣列{2,3,1,0,2,5,3},那麼對應輸出的是重複的數字2或者3。
java程式碼實現如下:

/**
 * @author FengTianHao
 * @version 1.0
 * @since 2018/11/20 9:08
 */

import com.sun.istack.internal.localization.NullLocalizable;

/** 找出陣列中重複的數字--最優演算法
 * 思路:
 *  從頭到尾依次掃描這個陣列中的每個數字當掃描到下標為i的數字時(比如a[i]),首先比較這個數字(用a[i]表示)
 *  等不等於i,如果(a[i]==i)接著掃描下一個數字;如果當前的數字(a[i])和下標i的值不相等,則再比較a[i]和陣列中的下標
 *  等於a[i]的數字,如果二者相等則找到重複值;如果不相等則對這兩個數進行互動。接下來重複這個比較
 *  、交換的過程,直到我們發現一個重複的數字
 */
public class Test{
    private int a;
    public void setA(int a)
    {
        this.a=a;
    }
    public int getA()
    {
        return a;
    }
    public static boolean duplicate(int[] numbers,Test duplication)
    {
        /**
         * 判斷陣列是否為空
         */
        if(numbers.length==0)
        {
            return false;
        }
        /**
         * 判斷陣列內的資料是否符合題目要求
         */
        for(int i=0;i<numbers.length;i++)
        {
            if(numbers[i]<0||numbers[i]>numbers.length-1)
            {
                return false;
            }
        }
        /**
         *  核心演算法
         */
        for(int i=0;i<numbers.length;i++)
            while (numbers[i] != i) {
                if (numbers[i] == numbers[numbers[i]]) {
                    duplication.setA(numbers[i]);
                    return true;
                }
                int temp;
                temp = numbers[i];
                numbers[i] = numbers[temp];
                numbers[temp] = temp;
            }
        return false;
    }
    public static void main(String[] args)
    {
        Test dup=new Test();
        int[] a=new int[]{2,3,1,0,2,5,3};
        if(duplicate(a,dup))
        {
            System.out.println("重複值為:"+dup.getA());
        }
        else
        {
            System.out.println("該陣列無重複值");
        }
    }
}
演算法執行過程:
以{2,3,1,0,2,5,3}為例
陣列的第0個數字(從0開始計數,和陣列的下標保持一致)是2,與它的下標值不相等,於是它
和下標為2的1進行比較,不相等,因此將2和下標為2的1進行交換。交換後的陣列是{1,3,2,0,2,5,3},
此時第0個數字1依舊和下標值不相等,於是將1和下標為1的3進行比較,不相等,因此將1和下標
為1的3進行交換,交換後的陣列為{3,1,2,0,2,5,3}。重複上述步驟繼續進行交換,交換後陣列
為{0,1,2,3,2,5,3},接下來掃描的是下標為4 的2,2和下標值不同,因此將2和下標為2的2進行
比較發現相同,則將2儲存,此時已經發現重複值,程式結束。




小結

程式碼中儘管有兩重迴圈,但是每個數字最多交換兩次就能找到屬於它的位置,因此總的時間複雜度為0(n).另外,所有的操作步驟都是在輸入陣列上進行的,不需要額外分配記憶體,因此空間複雜度為O(1);