每日算法題 | 劍指offer (2) 數組中重複的數字

重磅乾貨,第一時間送達
每日算法題 | 劍指offer (2) 數組中重複的數字

題目

數組中重複的數字

題目要求

在一個長度爲n的數組裏的所有數字都在0到n-1的範圍內。數組中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出數組中任意一個重複的數字。例如,如果輸入長度爲7的數組{2,3,1,0,2,5,3},那麼對應的輸出是第一個重複的數字2。

解題思路

題目要求中可以發現,需要找出數組中重複的數字,長度爲n的數組中必定存在元素是重複的!那麼肯定是需要記錄數組元素出現的次數,一遇到2立馬跳出即可。所以我們需要額外的內存來記錄,這個時候你想到使用什麼樣的數據結構?

我們拋開這道題,假設現在題目沒有告訴你數組中是否存在元素重複,那假設現在利用剛剛題目的思路下來,當n較大的時候可能複雜度較高了。

我的想法就是將數組和集合結合下,先看看有沒有重複。不知道小夥伴們有沒有其他更好的思路?

用哈希表(字典)將出線的次數進行存儲
PS:其實可以不用擴展內存來解這道題的。

代碼實現

Python實現

# -*- coding:utf-8 -*-
class Solution:
    # 這裏要特別注意~找到任意重複的一個值並賦值到duplication[0]
    # 函數返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        if numbers==None or len(numbers)<=1:
            return False

        usedDic=set() #集合
        for i in range(len(numbers)):
            if numbers[i]<0 or numbers[i]>len(numbers)-1:
                return False
            if numbers[i] not in usedDic:
                usedDic.add(numbers[i])
            else:
                duplication[0]=numbers[i]
                return True
        return False

C++

bool duplicate(int numbers[], int length, int* duplication) {
        int flag = 0;
        sort(numbers,numbers+length);
        for(int i = 0; i<length-1; i++){
            if(numbers[i] == numbers[i+1]){
                * duplication = numbers[i];
                flag = 1;
            }
        }
        if(flag == 0) {* duplication = -1; return false;}
        if(flag == 1) return true;
}

JAVA

 public boolean duplicate(int numbers[],int length,int [] duplication) {
        if (length < 2 || numbers == null) {
            return false;
        }
        // 是否有重複值
        boolean isSuccess = false;
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < length; i++) {
            if (!map.containsKey(numbers[i])) {
                map.put(numbers[i], 1);
            } else {
                int b = map.get(numbers[i]);
                map.put(numbers[i], b+1);
                isSuccess = true;
            }
        }
        for (int i = 0; i < length; i++) {
            if (map.get(numbers[i]) > 1){
                duplication[0] = numbers[i];
                return isSuccess;
            }
        }
        return isSuccess;
    }

做法2:假設現在不能使用額外的空間進行運算。

從頭到尾掃描數組的每個數字,當掃描到下標爲i的數字時,首先比較這個數字(假設爲m)是否等於i,如果是,接着掃描下一個數字;如果不是,那麼再將它和下標爲m的數字對比,如果兩者不相等,就把它和第m個數字交換,把m放到屬於它的位置,如果兩者相等,那麼就找到了一個重複的數字。重複這個過程,知道發現一個重複的數字。

根據代碼分析複雜度:所有操作都在輸入數組上進行,不需要額外分配空間,因此空間複雜度爲O(1);儘管代碼中有一個兩重循環,但是每個數字最多隻要交換兩次就能找到它自己的位置,因爲總的時間複雜度爲O(n)

Python實現

# -*- coding:utf-8 -*-
class Solution:
    # 這裏要特別注意~找到任意重複的一個值並賦值到duplication[0]
    # 函數返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        if numbers==None or len(numbers)<=1:
            return False

        for i in range(len(numbers)):
            if numbers[i]<0 or numbers[i]>len(numbers)-1:
                return False

        for i in range(len(numbers)):
            while (numbers[i]!=i):
                if numbers[i]==numbers[numbers[i]]:
                    duplication[0]=numbers[i]
                    return True
                else:
                    temp=numbers[i]
                    numbers[i]=numbers[temp]
                    numbers[temp]=temp
        return False

後記

注:面試季來了,不管是作爲面試者還是以後作爲面試官,瞭解算法這門程序員之間的溝通方式都是非常必要的。找過工作的朋友應該都聽說過《劍指offer》,雖然書中只有六十多道題目,但是道道都是經典。

如果是單純的面試需求,劍指offer的優先級肯定是在Leetcode之前,總的說它有三個優點:

  • 1.很可能在面試中出現原題
  • 2.約66題,題量少,但是涵蓋的內容較全
  • 3.能培養一個良好的刷題習慣

它的缺點是:

  • 1.只有66題,刷着容易過擬合
  • 2.動態規劃的題比較少,因此需要在Leetcode上專項訓練。
    算法題主要分成數據結構和具體算法部分,簡單歸類如下。基本每道題都很精彩,所以這裏就不一一洗寫了,題解可以看看我的代碼倉庫或者討論區的內容。

數據結構類題目

  • LinkedList
  • 003-從尾到頭打印鏈表
  • 014-鏈表中倒數第k個結點
  • 015-反轉鏈表
  • 016-合併兩個或k個有序鏈表
  • 025-複雜鏈表的複製
  • 036-兩個鏈表的第一個公共結點
  • 055-鏈表中環的入口結點
  • 056-刪除鏈表中重複的結點
  • Tree
  • 004-重建二叉樹
  • 017-樹的子結構
  • 018-二叉樹的鏡像
  • 022-從上往下打印二叉樹
  • 023-二叉搜索樹的後序遍歷序列
  • 024-二叉樹中和爲某一值的路徑
  • 026-二叉搜索樹與雙向鏈表
  • 038-二叉樹的深度
  • 039-平衡二叉樹
  • 057-二叉樹的下一個結點
  • 058-對稱的二叉樹
  • 059-按之字形順序打印二叉樹
  • 060-把二叉樹打印成多行
  • 061-序列化二叉樹
  • 062-二叉搜索樹的第k個結點
  • Stack & Queue
  • 005-用兩個棧實現隊列
  • 020-包含min函數的棧
  • 021-棧的壓入、彈出序列
  • 044-翻轉單詞順序列(棧)
  • 064-滑動窗口的最大值(雙端隊列)
  • Heap
  • 029-最小的K個數
  • Hash Table
  • 034-第一個只出現一次的字符
  • 065-矩陣中的路徑(BFS)
  • 066-機器人的運動範圍(DFS)
  • 具體算法類題目
  • 斐波那契數列
  • 007-斐波拉契數列
  • 008-跳臺階
  • 009-變態跳臺階
  • 010-矩形覆蓋
  • 搜索算法
  • 001-二維數組查找
  • 006-旋轉數組的最小數字(二分查找)
  • 037-數字在排序數組中出現的次數(二分查找)
  • 全排列
  • 027-字符串的排列
  • 動態規劃
  • 030-連續子數組的最大和
  • 052-正則表達式匹配(我用的暴力)
  • 回溯
  • 065-矩陣中的路徑(BFS)
  • 066-機器人的運動範圍(DFS)
  • 排序
  • 035-數組中的逆序對(歸併排序)
  • 029-最小的K個數(堆排序)
  • 029-最小的K個數(快速排序)
  • 位運算
  • 011-二進制中1的個數
  • 012-數值的整數次方
  • 040-數組中只出現一次的數字
  • 其他算法
  • 002-替換空格
  • 013-調整數組順序使奇數位於偶數前面
  • 028-數組中出現次數超過一半的數字
  • 031-整數中1出現的次數(從1到n整數中1出現的次數)
  • 032-把數組排成最小的數
  • 033-醜數
  • 041-和爲S的連續正數序列(滑動窗口思想)
  • 042-和爲S的兩個數字(雙指針思想)
  • 043-左旋轉字符串(矩陣翻轉)
  • 046-孩子們的遊戲-圓圈中最後剩下的數(約瑟夫環)
  • 051-構建乘積數組

劍指offer刷題交流羣

掃碼添加微信,一定要備註研究方向+地點+學校+暱稱(如機器學習+上海+上交+湯姆)

每日算法題 | 劍指offer (2) 數組中重複的數字
▲長按加羣

每日算法題 | 劍指offer (2) 數組中重複的數字

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章