劍指offer(python)--數值

題目描述
把只包含質因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因爲它包含質因子7。 習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。

思路:
在這裏插入圖片描述

# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        if index == 0:
            return 0
        # 1作爲特殊數直接保存
        baselist = [1]
        min2 = min3 = min5 = 0
        curnum = 1
        while curnum < index:
            minnum = min(baselist[min2] * 2, baselist[min3] * 3, baselist[min5] * 5)
            baselist.append(minnum)
            # 找到第一個乘以2的結果大於當前最大丑數M的數字,也就是T2
            while baselist[min2] * 2 <= minnum:
                min2 += 1
            # 找到第一個乘以3的結果大於當前最大丑數M的數字,也就是T3
            while baselist[min3] * 3 <= minnum:
                min3 += 1
            # 找到第一個乘以5的結果大於當前最大丑數M的數字,也就是T5
            while baselist[min5] * 5 <= minnum:
                min5 += 1
            curnum += 1
        return baselist[-1]
        
原文:https://blog.csdn.net/qq_20141867/article/details/81060581 

數值的次方

題目描述
給定一個double類型的浮點數base和int類型的整數exponent。求base的exponent次方。

思路:

這道題看似簡單,其實BUG重重。要注意的問題:

1 關於次冪的問題特殊的情況,比如次冪爲負數,或者基數爲0時等等複雜的情況
2. 機器中浮點數的比較是由誤差的,因此double類型的比較,不能用簡單的a==0來比較。一般的比較方式是,相減的差在一個很小的區間內,我們就認爲是相等的。

思路:首先考慮base在-0.00001到0.00001之間的數,其接近於0,所以其指數次輸出爲0,對於指數爲0的任意非0數結果爲1,對於指數冪爲1的任意數結果爲base本身,對於其他的base值,當指數爲正數時,直接相乘即可,對於指數爲負數時,先將其轉換爲正的指數,相乘的結果再取倒數即可。
即分情況討論即可

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        if base==0:
            return 0
        elif exponent==0:
            return 1
        elif exponent==1:
            return base
        else:
            return pow(base,exponent)

題目描述
輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。

問題:1. 輸入整數,可能是正,可能是負,或者是0
2.整數轉變爲二進制如何轉變?如何計算1的個數
python中 可以使用bin(n).count(‘1’)這個做法,但是需要單獨考慮因爲n是負數時該式子不成立
3.補碼是什麼? 負數如何用補碼

複習:

一個數在計算機中的二進制表示形式, 叫做這個數的機器數。機器數是帶符號的,在計算機用一個數的最高位存放符號, 正數爲0, 負數爲1
原碼:
原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其餘位表示值. 比如8位二進制1,-1的原碼如下
8----- [+1]原 = 00000001
[-1]原 = 1000 0001
第一位是符號位. 因爲第一位是符號位, 所以8位二進制數的取值範圍就是: [1111 1111, 0111 1111] 即 [-127 , 127]
反碼:正數的反碼是其本身,負數的反碼是在其原碼的基礎上,符號位不變,其餘各個位取反. [+1] = [00000001] 原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
補碼:正數的補碼就是其本身,負數的補碼是在其原碼的基礎上, 符號位不變, 其餘各位取反, 最後+1.
(即在反碼的基礎上+1)

如何獲得二進制數?
”方法1: 用2輾轉相除直到結果爲1,將餘數和最後的1從下向上的組合,就是我們想要的結果

python中 可以使用bin(n).count(‘1’)這個做法,但是需要單獨考慮因爲n是負數時該式子不成立

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        cnt = 0
        if n < 0:
            n = n & 0xffffffff
        return bin(n).count('1')

帶self 參數就需要建立class類

輸入一個負整數看看,程序會陷入死循環,因爲在其他語言中,負數在計算機中是用補碼錶示的,最高位是1,在右移的過程中,高位都是用1來填補的,所以while num這個條件一直爲真;在python中,根據右移的定義就可以自行推斷出來。既然現在右移num不行,那我們可以左移1,在32的整數中,最多左移32位,1就會變爲零,所以這可以作爲判斷條件,在python中,我們一起可以左移下去(到虛擬內存大小的位數),
可以使用一個mask來表示正在看到的位數,循環32次,那麼就得到了每一個位置上是1的個數

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        mask = 1
        cnt = 0
        for i in range(32):
            if n & mask:
                cnt += 1
            mask <<= 1
        return cnt 

https://www.jianshu.com/p/e29d64d8f1c3

`
https://www.jianshu.com/p/e29d64d8f1c3

方法2:是用位運算,將1每次左移,和數字進行&運算,如果成功,則返回1

技巧:python中的左移和右移與其他C/C++等的定義和結果都是不一樣的,大家可以自行做實驗,python中的定義:右移n位定義爲除以pow(2,n),左移n位定義爲乘以pow(2,n),而且沒有溢出(移除的int會升級爲long類型)

`n-1會讓n最右邊的1變爲0,其左邊所有的數字都不會改變,所以每 n = (n-1)&n一次,n就少一個1

class Solution:
    def NumberOf1(self, n):
        total =0
        if n==0:
            return 0
        if n<0:
            n=n & 0xffffffff  # 這一步是關於負數運算的
        while n:
            n=n&(n-1)  #按位與 
            total+=1
        return total
        

class Solution:
    def numberOf1(self, n):
        total = 0
        if n == 0:
            return 0
            if n < 0:
                n = n & 0xffffffff
                while n:
                    n = n & (n - 1)
                    total += 1
                    return total


if __name__ == '__main__':
    demo=Solution()

    print(demo.numberOf1(9))

爲什麼這個輸出是none

拓展:
位運算n&(n-1)的使用

按位與的知識
n&(n-1)作用:將n的二進制表示中的最低位爲1的改爲0,先看一個簡單的例子: n = 10100(二進制),則(n-1) = 10011
==》n&(n-1) = 10000 可以看到原本最低位爲1的那位變爲0。
1、 判斷一個數是否是2的方冪
n > 0 && ((n & (n - 1)) == 0 )

解釋((n & (n-1)) == 0):

如果A&B==0,表示A與B的二進制形式沒有在同一個位置都爲1的時候。

那麼本題到底啥意思??

不妨先看下n-1是什麼意思。

令:n=1101011000(二進制,十進制也一樣),則

n-1=1101010111。

n&(n-1)=1101010000

由此可以得出,n和n-1的低位不一樣,直到有個轉折點,就是借位的那個點,從這個點開始的高位,n和n-1都一樣,如果高位一樣這就造成一個問題,就是n和n-1在相同的位上可能會有同一個1,從而使((n
& (n-1)) != 0),如果想要

((n & (n-1)) == 0),則高位必須全爲0,這樣就沒有相同的1。

所以n是2的冪或0

  1. 求某一個數的二進制表示中1的個數 while (n >0 ) {
    count ++;
    n &= (n-1); }

  2. 計算N!的質因數2的個數。 容易得出N!質因數2的個數 = [N / 2] + [N / 4] + [N / 8] + …. 下面通過一個簡單的例子來推導一下過程:N = 10101(二進制表示) 現在我們跟蹤最高位的1,不考慮其他位假定爲0, 則在 [N / 2]
    01000 [N / 4] 00100 [N / 8] 00010 [N / 8] 00001 則所有相加等於01111
    = 10000 - 1 由此推及其他位可得:(10101)!的質因數2的個數爲10000 - 1 + 00100 - 1 + 00001 - 1 = 10101 - 3(二進制表示中1的個數)

推及一般N!的質因數2的個數爲N-(N二進制表示中1的個數)

順時針打印矩陣

題目描述
輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每一個數字,例如,如果輸入如下4 X 4矩陣:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
則依次打印出數字
1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

解析:由於題目是以從外圈到內圈的順序依次打印,在矩陣中標註一圈作爲分析的目標。設矩陣的寬度爲cols,而其高度爲rows。選取左上角座標爲(startX, startY),右下角座標爲(endX, endY)的一個圈來分析。
在這裏插入圖片描述
由於endX和endY可以根據startX、startY以及columns、rows來求得,因此此時我們只需要引入startX和startY兩個變量。我們可以想象有一個循環,在每一次循環裏我們從(startX, startY)出發按照順時針打印數字。
接着分析這個循環結束的條件。對一個5×5的矩陣而言,最後一圈只有一個數字,對應的座標爲(2, 2)。我們發現5 > 2 * 2。對一個6×6的矩陣而言,最後一圈有四個數字,對應的座標仍然爲(2, 2)。我們發現6 > 2 * 2依然成立。於是我們可以得出,讓循環繼續的條件是“cols > startX * 2 && rows > startY * 2”。

  接下來我們分析如何按照順時針的順序打印一圈的數字。我們可以分四步來打印:第一步是從左到右打印一行,第二步是從上到下打印一列,第三步從右到左打印一行,最後一步是從下到上打印一列。也就是我們把打印一圈數字這個問題,分解成四個子問題。


值得注意的是,最後一圈可能退化成只有一行、只有一列、甚至只有一個數字,因此打印這樣的一圈就不需要四步了。
原文:https://blog.csdn.net/yanxiaolx/article/details/52254590

 def printMatrix(self, matrix):
        # write code here
        if matrix==[[]]:
            return
        row=len(matrix)
        column=len(matrix[0])
        left=0
        right=column-1
        top=0
        boom=row-1
        res=[]
        while right>left and top<boom:
            #從左到右
            for i in range(left,right+1):
                res.append(matrix[top][i])
            #從上到下
            for i in range(top+1,boom+1):
                res.append(matrix[i][right])
            #從右到左
            for i in range(right-1,left-1,-1):
                res.append(matrix[boom][i])
            #從下到上
            for i in range(boom-1,top,-1):
                res.append(matrix[i][left])
            left+=1
            right-=1
            top+=1
            boom-=1
        #剩下一行
        if boom==top and left<right:
            for i in range(left,right+1):
                res.append(matrix[boom][i])
        #剩下一列
        if left==right and boom>top:
            for i in range(top,boom+1):
                res.append(matrix[i][left])
        #剩下一個
        if boom==top and left==right:
            res.append(matrix[left][top])
        return res

原文:https://blog.csdn.net/yangnianjinxin/article/details/79243110 

和爲s的連續正數序列

題目描述
小明很喜歡數學,有一天他在做數學作業時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他並不滿足於此,他在想究竟有多少種連續的正數序列的和爲100(至少包括兩個數)。沒多久,他就得到另一組連續正數和爲100的序列:18,19,20,21,22。現在把問題交給你,你能不能也很快的找出所有和爲S的連續正數序列? Good Luck!

輸出描述:

輸出所有和爲S的連續正數序列。序列內按照從小至大的順序,序列間按照開始數字從小到大的順序

思路

# -*- coding:utf-8 -*-
class Solution:
    def FindContinuousSequence(self, tsum):
        res=[]
        for i in range(1,tsum//2+1):
            sumRes=i
            for j in range(i+1,tsum//2+2):
                sumRes+=j
                if sumRes==tsum:
                    res.append(list(range(i,j+1)))
                    break
                elif sumRes>tsum:
                    break
        return res

-和爲s的兩個數字

題目描述
輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,使得他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。

輸出描述: 對應每個測試案例,輸出兩個數,小的先輸出。

不需要判斷最小的

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        for i in array:
            if tsum-i in array:
                if tsum-i==i:
                    if array.count(i)>1:
                        return [i,i]
                else:
                    return [i,tsum-i]
        return []

下面這個是我自己寫的,通過

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        list=[]
        n=len(array)
        for i in range(0,n-1):
            for j in range(i+1,n):
                if array[i]+array[j]==tsum:
                    list.append([array[i],array[j]])
        if list==[]:
            return []
        return min(list)

題目描述
牛客最近來了一個新員工Fish,每天早晨總是會拿着一本英文雜誌,寫些句子在本子上。同事Cat對Fish寫的內容頗感興趣,有一天他向Fish借來翻看,但卻讀不懂它的意思。例如,“student. a am I”。後來才意識到,這傢伙原來把句子單詞的順序翻轉了,正確的句子應該是“I am a student.”。Cat對一一的翻轉這些單詞順序可不在行,你能幫助他麼?


思路:
1,使用空格或者特殊字符把字符串轉換爲多個單詞字符串,然後存在列表裏,
2,列表翻轉,再進行連接


-- coding:utf-8 --

class Solution:
def ReverseSentence(self, s):
str1=s.split(’ ') #
lists=[]
for i in str1:
lists.append(i)
return ’ '.join(lists[::-1])


## 矩陣中的路徑*** 機器人的運動範圍
題目描述
請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則之後不能再次進入這個格子。 例如 a b c e s f c s a d e e 這樣的3 X 4 矩陣中包含一條字符串"bcced"的路徑,但是矩陣中不包含"abcb"路徑,因爲字符串的第一個字符b佔據了矩陣中的第一行第二個格子之後,路徑不能再次進入該格子。
思路:
回溯法,遍歷矩陣中的每一個位置

-- coding:utf-8 --

class Solution:
def hasPath(self, matrix, rows, cols, path):
for i, s in enumerate(matrix):
if s==path[0] and self.visit([(i//cols, i%cols)], matrix, rows, cols, path):
return True
return False

def visit(self, ans, matrix, rows, cols, path):
    if len(ans)==len(path):
        return True
    i,j = ans[-1]
    nex = [(ii,jj) for ii,jj in [(i,j-1),(i,j+1),(i-1,j),(i+1,j)]
           if 0<= ii <rows and 0<= jj <cols and 
           (ii,jj) not in ans and
           matrix[ii*cols +jj]==path[len(ans)]]
    return sum([self.visit(ans+[x], matrix, rows, cols, path) for x in nex])

題目描述
地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人能夠進入方格(35,37),因爲3+5+3+7 = 18。但是,它不能進入方格(35,38),因爲3+5+3+8 = 19。請問該機器人能夠達到多少個格子?

思路:將地圖全部置1,遍歷能夠到達的點,將遍歷的點置0並令計數+1.這個思路在找前後左右相連的點很有用,比如leetcode中的海島個數問題/最大海島問題都可以用這種方法來求解。

class Solution:
def init(self):
self.count = 0

def movingCount(self, threshold, rows, cols):
    # write code here
    arr = [[1 for i in range(cols)] for j in range(rows)]
    self.findway(arr, 0, 0, threshold)
    return self.count

def findway(self, arr, i, j, k):
    if i < 0 or j < 0 or i >= len(arr) or j >= len(arr[0]):
        return
    tmpi = list(map(int, list(str(i))))
    tmpj = list(map(int, list(str(j))))
    if sum(tmpi) + sum(tmpj) > k or arr[i][j] != 1:
        return
    arr[i][j] = 0
    self.count += 1
    self.findway(arr, i + 1, j, k)
    self.findway(arr, i - 1, j, k)
    self.findway(arr, i, j + 1, k)
    self.findway(arr, i, j - 1, k)
## 求1到N加法,做加法
題目描述
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。

思路:直接套公式

-- coding:utf-8 --

class Solution:
def Sum_Solution(self, n):
return n*(n+1)/2
# write code here


題目描述
寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號。

思路:可以採用位操作來實現,利用異或運算來計算不帶進位的加法結果,利用與運算計算進位的標誌,然後將這兩個結果進行不帶進位相加,重複上述過程,直至進位標誌位0
鏈接:https://www.nowcoder.com/questionTerminal/59ac416b4b944300b617d4f7f111b215
來源:牛客網

同樣我們可以用三步走的方式計算二進制值相加: 5-101,7-111 第一步:相加各位的值,不算進位,得到010,二進制每位相加就相當於各位做異或操作,101^111。

第二步:計算進位值,得到1010,相當於各位做與操作得到101,再向左移一位得到1010,(101&111)<<1。

第三步重複上述兩步, 各位相加 010^1010=1000,進位值爲100=(010&1010)<<1。
     繼續重複上述兩步:1000^100 = 1100,進位值爲0,跳出循環,1100爲最終結果。
  
計算兩個數字的異或值,相當於只計算每一位的和,不計算進位,得出結果sum;

2.計算兩個數字的與值,相當於求出兩個數字的進位,然後左移一位,相當於進位,得出結果jw

-- coding:utf-8 --

class Solution:
def Add(self, num1, num2):
# write code here
while num2 != 0:
temp = num1 ^ num2
num2 = (num1 & num2) << 1
num1 = temp & 0xFFFFFFFF
return num1 if num1 >> 31 == 0 else num1 - 4294967296

## -翻轉單詞順序列
題目描述
牛客最近來了一個新員工Fish,每天早晨總是會拿着一本英文雜誌,寫些句子在本子上。同事Cat對Fish寫的內容頗感興趣,有一天他向Fish借來翻看,但卻讀不懂它的意思。例如,“student. a am I”。後來才意識到,這傢伙原來把句子單詞的順序翻轉了,正確的句子應該是“I am a student.”。Cat對一一的翻轉這些單詞順序可不在行,你能幫助他麼?


思路:
1,使用空格或者特殊字符把字符串轉換爲多個單詞字符串,然後存在列表裏,
2,列表翻轉,再進行連接


-- coding:utf-8 --

class Solution:
def ReverseSentence(self, s):
str1=s.split(’ ') #
lists=[]
for i in str1:
lists.append(i)
return ’ '.join(lists[::-1])

## 撲克牌順子****
題目描述
LL今天心情特別好,因爲他去買了一副撲克牌,發現裏面居然有2個大王,2個小王(一副牌原本是54張^_^)...他隨機從中抽出了5張牌,想測測自己的手氣,看看能不能抽到順子,如果抽到的話,他決定去買體育彩票,嘿嘿!!“紅心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是順子.....LL不高興了,他想了想,決定大\小 王可以看成任何數字,並且A看作1,J爲11,Q爲12,K爲13。上面的5張牌就可以變成“1,2,3,4,5”(大小王分別看作2和4),“So Lucky!”。LL決定去買體育彩票啦。 現在,要求你使用這幅牌模擬上面的過程,然後告訴我們LL的運氣如何, 如果牌能組成順子就輸出true,否則就輸出false。爲了方便起見,你可以認爲大小王是0。

思路:

> 鏈接:https://www.nowcoder.com/questionTerminal/762836f4d43d43ca9deb273b3de8e1f4
來源:牛客網
> 
> 這道題很簡單,注意兩點 
> 1、如果輸入爲空,返回false
>  2、除了王的任何某個特定數值的牌出現兩張或者更多,那麼一定湊不齊順子。
> 思路,先統計王的數量,再把牌排序,如果後面一個數比前面一個數大於1以上,那麼中間的差值就必須用王來補了。看王的數量夠不夠,如果夠就返回true,否則返回false。
思路:
1)沒有大小王的時候即判斷數是否連續;
2)有大小王的時候,判斷數的間隔是否小於王的數量。小於返回true,大於返回false;
3)有相等的牌則直接返回false。


鏈接:https://www.nowcoder.com/questionTerminal/762836f4d43d43ca9deb273b3de8e1f4
來源:牛客網

    class Solution:
        def IsContinuous(self, numbers):
            # write code here
            if len(numbers) < 5:
                return False
            #計算0的個數
            nOfZero = numbers.count(0)
            #排序
            numbers.sort()
            #序列中間隔的值初始化爲0
            sumOfGap=0
            #遍歷非0部分的遞增序列
            for i in range(nOfZero, len(numbers) - 1):
                small = numbers[i]
                big = numbers[i + 1]
                #當前與下一個值的比較,若相等則說明存在對子
                if small == big:
                    return False
                else:
                    #若不同,則得到二者的差再減1,若爲0則說明連續,否則二者之間存在空缺
                    sumOfGap+= (big-small - 1)
                    #判斷0的個數及序列中非0部分間隔值,若0不小於間隔值,則說明滿足連續條件
            if nOfZero >= sumOfGap:
                return True
            else:
                return False
## 孩子們的遊戲
題目描述
每年六一兒童節,牛客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此。HF作爲牛客的資深元老,自然也準備了一些小遊戲。其中,有個遊戲是這樣的:首先,讓小朋友們圍成一個大圈。然後,他隨機指定一個數m,讓編號爲0的小朋友開始報數。每次喊到m-1的那個小朋友要出列唱首歌,然後可以在禮品箱中任意的挑選禮物,並且不再回到圈中,從他的下一個小朋友開始,繼續0...m-1報數....這樣下去....直到剩下最後一個小朋友,可以不用表演,並且拿到牛客名貴的“名偵探柯南”典藏版(名額有限哦!!^_^)。請你試着想下,哪個小朋友會得到這份禮品呢?(注:小朋友的編號是從0到n-1)

思路:
約瑟夫問題
一個重要的公式
![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20190223193426255.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI0NDI5MzMz,size_16,color_FFFFFF,t_70)
鏈接:https://www.nowcoder.com/questionTerminal/f78a359491e64a50bce2d89cff857eb6
來源:牛客網

    class Solution:
        def LastRemaining_Solution(self, n, m):
            if n < 1:
                return -1
             
            con = range(n)
             
            final = -1
            start = 0
            while con:
                k = (start + m - 1) % n
                final = con.pop(k)
                n -= 1
                start = k
                 
            return final

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