劍指offer(python)---數組類

01-二維數組的查找

題目描述
在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數

  • 方法1----暴力求解

思路1 :這個題目按照一般的想法就是雙層嵌套for語句, 容易出錯點分析:
1.數組下標越界 nRow-1,nCol-1 數組中的下標是從0開始的
2.沒有考慮到數組爲空的情況—考慮特殊情況
3.二維數組[[]]它不爲空,它是有一個元素爲列表,但列表爲空的數組,等價於if colcount == 0:#這裏要考慮到二維數組爲空的情況,如[[]]
知道行數和列數逐一比較,複雜度是行數乘以列數

class Solution:
    def Find(self, target, array):
        rows=len(array)
        cols=len(array[0])
        row=0
        col=0
        while row<rows and col<cols:
            if target==array[row][col]:
                return True
            elif target>array[row][col]:
                row+=1
            else:
                col+=1
        return False
        
import numpy as np
if __name__ == '__main__':
    a= np.array([[1,2,0,1],[1,6,9,55],[7,8,9,5]])
    target=4
    print(Solution().Find(target,a))
if __name__=='__main__':         
    a = Solution()
    print(a.Find([[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]],7))
  • 方法2-----有序求解

    因爲矩陣是有序的,從右上角來看,行數row, 列數cols, 向下數字遞增,向左數字遞減,因此從右上角開始查找,當要查找數字比右上角數字大時。列數左移;要查找數字比右上角數字小時,行數+1下移;複雜度是行數加上列數
    在這裏插入圖片描述

class Solution:
    # array 二維列表
    def Find(self, target, array):
        rows=len(array)
        cols=len(array[0])
        if rows>0 and cols>0:
            row=0
            col=cols-1
            while row<rows and col>=0:
                if target==array[row][col]:
                    return True
                elif target>array[row][col]:
                    row+=1
                else:
                    col-=1
            return False

02-數組中重複的數字

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

  • 方法1—字典映射
    -設置空字典,如果在字典裏,value值加1,不在的話設置爲1,通過map字典確定。然後再從字典裏取出首個重複的數字。
class Solution:
    # 這裏要特別注意~找到任意重複的一個值並賦值到duplication[0]
    # 函數返回True/False
    def duplicate(self, numbers, duplication):
        dict={}
        for num in numbers:
            if num not in dict:
                dict[num]=1
            else:
                dict[num]+=1
        for k in dict:
            if dict[k]>=2:
                duplication[0]=k
                return True
        return False

03-構建乘積數組

題目描述
給定一個數組A[0,1,…,n-1],請構建一個數組B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。(注意:規定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)

  • 方法1–直接法

思路:按上圖把每行被1分割的兩部分乘積都計算出來,這樣可以從首尾分別用累乘算出兩個列表,然後兩個列表首尾相乘就是B的元素
在這裏插入圖片描述

解釋下代碼,設有數組大小爲5。 對於第一個for循環
第一步:b[0] = 1;
第二步:b[1] = b[0] * a[0] = a[0]
第三步:b[2] = b[1] * a[1] = a[0] * a[1];
第四步:b[3] = b[2] * a[2] = a[0] *a[1] * a[2];
第五步:b[4] = b[3] * a[3] = a[0] * a[1] * a[2] * a[3];
然後對於第二個for循環
第一步 temp *= a[4] = a[4];
b[3] = b[3] * temp = a[0] *a[1] * a[2] * a[4];
第二步 temp *= a[3] = a[4] * a[3]; b[2] = b[2] * temp= a[0] * a[1] * a[4] * a[3];
第三步 temp *= a[2] = a[4] * a[3] * a[2]; b[1] = b[1] * temp = a[0] * a[4] * a[3] * a[2];
第四步 temp *= a[1] = a[4] * a[3] * a[2] * a[1]; b[0] = b[0] * temp = a[4] * a[3] * a[2] *
a[1]; 由此可以看出從b[4]到b[0]均已經得到正確計算。

class Solution:
    def multiply(self, A):
        B = [1]*len(A)  #將1複製len(A)次
        for i in range(0,len(A)):
            for j in range(0,len(B)):
                if i!=j:
                    B[i] *= A[j]
        return B

04- 空格替換

題目描述 2請實現一個函數,將一個字符串中的每個空格替換成“%20”。例如,當字符串爲We Are
Happy.則經過替換之後的字符串爲We%20Are%20Happy。

  • 方法1:直接使用replace函數
# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        return s.replace(' ','%20')
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        return "%20".join(list(s.split(" ")))

. join(): 連接字符串數組。將字符串、元組、列表中的元素以指定的字符(分隔符)連接生成一個新的字符串

  • 方法2–直接替換
python
# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        new_s = ''
        for j in s:
            if j == ' ':
                new_s=new_s + '%20'
            else:
                new_s=new_s + j
        return new_s

05–旋轉數組的最小元素

把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。 輸入一個非減排序的數組的一個旋轉,輸出旋轉數組的最小元素。
例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。
NOTE:給出的所有元素都大於0,若數組大小爲0,請返回0。

思路1:對於數組中的元素,兩兩比較

方法1–兩兩比較

class Solution:
    def minNumberInRotateArray(self, array):
        if len(array)==0:
            return 0
        i=0
        for i in range(len(array)):
            if (array[i]>array[i+1]):
                return array[i+1]
        return array[0]

思路2:二分查找法

class Solution:
    def minNumberInRotateArray(self, array):
        if len(array) ==0:
            return 0
        left=0
        right = len(array)-1
        mid=-1
        while(array[left]>array[right]):
            if(right-left==1):
                mid=right
                break
        mid=left+(right-left)/2
        if(array[mid]>=array[left]):
            left=mid
        if (array[mid]<array[right]):
            right=mid
        return array[mid]
循環太大

思路3–sort排序

方法3:先sort排序
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if not rotateArray:
            return 0
        else:
            rotateArray.sort()
            return rotateArray[0]

思路4–直接min函數

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if not rotateArray:
            return 0
        else:
            return min(rotateArray)

07-函數調整順序

題目描述
輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得所有的奇數位於數組的前半部分,所有的偶數位於數組的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。
思路1:用兩個數組

class Solution:
    def reOrderArray(self, array):
        l1=[]
        l2=[]
        for i in range(len(array)):
            if array[i]%2==0:
                l2.append(array[i])
            else:
                l1.append(array[i])
        return l1+l2

## 08-查找數組中次數較多的元素
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。
思路--這種類型的通過字典映射

```python
# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        dict={}
        for num in numbers:
            if num not in dict:
                dict[num]=1
            else:
                dict[num]+=1
            if dict[num]>len(numbers)/2:
                return num
        return 0

09-連續子數組的最大和

HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全爲正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和爲8(從第0個開始,到第3個爲止)。給一個數組,返回它的最大連續子序列的和,你會不會被他忽悠住?(子向量的長度至少是1)

  • 思路:1、第一個不爲負數

2、如果前面數的累加值加上當前數後的值會比當前數小,說明累計值對整體和是有害的;如果前面數的累加值加上當前數後的值比當前數大或者等於,則說明累計值對整體和是有益的。
步驟:

1、定義兩個變量,一個用來存儲之前的累加值,一個用來存儲當前的最大和。遍歷數組中的每個元素,假設遍歷到第i個數時:

①如果前面的累加值爲負數或者等於0,那對累加值清0重新累加,把當前的第i個數的值賦給累加值。

②如果前面的累加值爲整數,那麼繼續累加,即之前的累加值加上當前第i個數的值作爲新的累加值。

2、判斷累加值是否大於最大值:如果大於最大值,則最大和更新;否則,繼續保留之前的最大和

class Solution:
    def FindGreatestSumOfSubArray(self, array):
        if len(array)<=0:
            return []
        temp=0
        linum=[]
        for i in array:
            temp=temp+i  注意這個是加i
            linum.append(temp)
            if temp>0:
                continue
            else:
                temp=0
        return max(linum)

10-連續子數組的最大和

輸入一個正整數數組,把數組裏所有數字拼接起來排成一個數,打印能拼接出的所有數字中最小的一個。例如輸入數組{3,32,321},則打印出這三個數字能排成的最小數字爲321323。
思路,轉化爲字符串進行比較,

# -*- coding:utf-8 -*-
  if not numbers: 
            return ""
        numbers = list(map(str, numbers))
        numbers.sort(cmp=lambda x, y: cmp(x + y, y + x)) #降序排列
        return "".join(numbers).lstrip('0') or'0'

11-數組中的逆序對

在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P對1000000007取模的結果輸出。
即輸出P%1000000007

思路1:
第一反應是順序掃描整個數組。每掃描到一個數組的時候,逐個比較該數字和它後面的數字的大小。如果後面的數字比它小,則這兩個數字就組成了一個逆序對。假設數組中含有n個數字。由於每個數字都要和O(n)這個數字比較,因此這個算法的時間複雜度爲O(n^2)。

def test(array):
    t=0
    for i in range(len(array)-1,0,-1):
        flag=False
        for j in range(i):
            if array[j]>array[j+1]:
                array[j],array[j+1]=array[j+1],array[j]
                t+=1
                flag=True
        if not flag:
            break
    return t%(2*(10**5))

但是這個時間複雜度太高,過不了

from collections import deque 
class Solution:
    def __init__(self):
        self.count = 0
    def InversePairs(self, lis):
        self.mergeSort(lis)
        return self.count%1000000007
    def mergeSort(self, lis):
        if len(lis) <= 1:
            return lis
        middle = int(len(lis)//2)
        left = self.mergeSort(lis[:middle])
        right = self.mergeSort(lis[middle:])
        return self.merge(left, right)                      
    def merge(self, left,right):
        merged,left,right = deque(),deque(left),deque(right)
        while left and right:
            if left[0] > right[0]:
                self.count += len(left)
                merged.append(right.popleft())
            else:
                merged.append(left.popleft())
        if right:
            merged.extend(right)
        else:
            merged.extend(left)
        return merged
  • 方法2

先將原序列排序,然後從排完序的數組中取出最小的,它在原數組中的位置表示有多少比它大的數在它前面,每取出一個在原數組中刪除該元素,保證後面取出的元素在原數組中是最小的,這樣其位置才能表示有多少比它大的數在它前面,即逆序對數。

class Solution:
    def InversePairs(self, data):
        count = 0
        copy = []
        for i in data:
            copy.append(i)
        copy.sort()
        for i in range(len(copy)):
            count += data.index(copy[i])
            data.remove(copy[i])
        return count%1000000007
a=[1,2,3,4,5,6,7,0]
Solution().InversePairs(a)

12–統計一個數字在排序數組中出現的次數。

class Solution:
    def GetNumberOfK(self, data, k):
        dict={}
        for num in data:
            if num not in dict:
                dict[num]=1
            else:
                dict[num]+=1
        if  k in dict:
            return dict[k]
        else:
            return 0

13-一個整型數組裏除了兩個數字之外,其他的數字都出現了偶數次。請寫程序找出這兩個只出現一次的數字。

也是使用字典

# -*- coding:utf-8 -*-
class Solution:
    # 返回[a,b] 其中ab是出現一次的兩個數字
    def FindNumsAppearOnce(self, array):
        hashMap = {}
        for i in array:
            if str(i) in hashMap:
                hashMap[str(i)] += 1
            else:
                hashMap[str(i)] = 1
        res = []
        for k in hashMap.keys():
            if hashMap[k] == 1:
                res.append(int(k))
        return res

09-數據流的中位數

如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取數據流,使用GetMedian()方法獲取當前讀取數據的中位數。
題目描述:
請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g"。當從該字符流中讀出前六個字符“google"時,第一個只出現一次的字符是"l"。

輸出描述: 如果當前字符流沒有存在出現一次的字符,返回#字符。

思路:
用字典(Java中的HashMap結構)來做。字典中的鍵值對中,鍵key存儲字符;值value存儲字符出現的次數。
和前面的那道字符串中只出現一次的字符相似而不相同,前面那道是固定長度字符串,而本題是字符流,也就是會增長的,每次字符串多一個字符,就要重新判斷是哪個只出現一次的字符

因爲牛客網裏劍指offer的python只有2.7,沒有3.0以上的版本,而python2.7的字典遍歷通常不是有序的(python3通常有序),所以只能再借助一個列表來存儲全部字符串,遍歷字符串從而尋找

class Solution:
    # 返回對應char
    def __init__(self):
        self.charDict = {}#存放字符和對應的數量
        self.charlist = []#存放字符
    def FirstAppearingOnce(self):
        # write code here
        for key in self.charlist:
            if self.charDict[key]==1:
                return key
        return '#'
    def Insert(self, char):
        # write code here
        self.charDict[char]=1 if char not in self.charDict else self.charDict[char]+1
        self.charlist.append(char)

其實再想一下,把字典去掉也完全可以啊,這跟那道固定長度的只出現一次字符串沒有本質的區別

class Solution:
    # 返回對應char
    def __init__(self):
        self.charlist = []
    def FirstAppearingOnce(self):
        # write code here
        for key in self.charlist:
            if self.charlist.count(key)==1:
                return key
        return '#'
    def Insert(self, char):
        # write code here
        self.charlist.append(char)

第二個作者

charDict = {}
def FirstAppearingOnce(self):
    for key in self.charDict:
        if self.charDict[key] == 1:
            return key
    return '#'

def Insert(self, char):
    self.charDict[char] = 1 if char not in self.charDict else self.charDict[char]+1
--------------------- 
作者:goddaniel 
來源:CSDN 
原文:https://blog.csdn.net/u010005281/article/details/80232522 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!
但上述代碼只能用於Python3。雖說Python中字典序爲無序,但默認情況下,Python3中的字典序爲“順序”,但Python2中存儲字典的算法和Python3中不同,遍歷字典鍵值對時的順序亦不同。

改進的思路是用列表存儲字符流中的順序,之後以列表中存入的字符流順序尋找第一個不重複的字符。但此法依舊只適用於Python3..

charDict = {}
list = []
def FirstAppearingOnce(self):
    for key in self.list:
        if self.charDict[key] == 1:
            return key
    return '#'

def Insert(self, char):
    self.charDict[char] = 1 if char not in self.charDict else self.charDict[char]+1
    self.list.append(char)
用字符串來存儲字符流的順序,適用於Python2,但不適用Python3..

charDict = {}
s = ""
def FirstAppearingOnce(self):
    for key in self.s:
        if self.charDict[key] == 1:
            return key
    return '#'

def Insert(self, char):
    self.charDict[char] = 1 if char not in self.charDict else self.charDict[char]+1
    self.s += char

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.arr=[]
    def Insert(self, num):
        self.arr.append(num)
        self.arr.sort()
    def GetMedian(self,fuck):
        length=len(self.arr)
        if length%2==1:
            return self.arr[length//2]
        else:
            return(self.arr[length//2]+self.arr[length//2-1])/2.0


## 滑動窗口的最大值
給定一個數組和滑動窗口的大小,找出所有滑動窗口裏數值的最大值。例如,如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那麼一共存在6個滑動窗口,他們的最大值分別爲{4,4,6,6,6,5}; 針對數組{2,3,4,2,6,2,5,1}的滑動窗口有以下6個: {[2,3,4],2,6,2,5,1}{2,[3,4,2],6,2,5,1}{2,3,[4,2,6],2,5,1}{2,3,4,[2,6,2],5,1}{2,3,4,2,[6,2,5],1}{2,3,4,2,6,[2,5,1]}。

```python
# -*- coding:utf-8 -*-
class Solution:
    def maxInWindows(self, nums, k):
        # write code here
        if not k or k>len(nums):return []
        cur_max = max(nums[:k])
        max_nums = [cur_max]
        for i in range(0, len(nums) - k):
            if nums[i] == cur_max:
                cur_max = max(nums[i + 1:i + k + 1])
            elif nums[i + k] > cur_max:
                cur_max = nums[i + k]
            max_nums.append(cur_max)
        return max_nums
        # write code here
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章