牛客网剑指offer编程实践31-40题
31、 整數(shù)中1出現(xiàn)的次數(shù)(從1到n整數(shù)中1出現(xiàn)的次數(shù))
求出1~13的整數(shù)中1出現(xiàn)的次數(shù),并算出100~1300的整數(shù)中1出現(xiàn)的次數(shù)?為此他特別數(shù)了一下1~13中包含1的數(shù)字有1、10、11、12、13因此共出現(xiàn)6次,但是對(duì)于后面問(wèn)題他就沒(méi)轍了。ACMer希望你們幫幫他,并把問(wèn)題更加普遍化,可以很快的求出任意非負(fù)整數(shù)區(qū)間中1出現(xiàn)的次數(shù)(從1 到 n 中1出現(xiàn)的次數(shù))。
解答:
方法:
設(shè)定整數(shù)點(diǎn)(如1、10、100等等)作為位置點(diǎn)i(對(duì)應(yīng)n的各位、十位、百位等等),分別對(duì)每個(gè)數(shù)位上有多少包含1的點(diǎn)進(jìn)行分析
1、根據(jù)設(shè)定的整數(shù)位置,對(duì)n進(jìn)行分割,分為兩部分,高位n/i,低位n%i
2、當(dāng)i表示百位,且百位對(duì)應(yīng)的數(shù)>=2,如n=31456,i=100,則a=314,b=56,此時(shí)百位為1的次數(shù)有a/10+1=32(最高兩位0~31),每一次都包含100個(gè)連續(xù)的點(diǎn),即共有(a%10+1)*100個(gè)點(diǎn)的百位為1
3、當(dāng)i表示百位,且百位對(duì)應(yīng)的數(shù)為1,如n=31156,i=100,則a=311,b=56,此時(shí)百位對(duì)應(yīng)的就是1,則共有a%10(最高兩位0-30)次是包含100個(gè)連續(xù)點(diǎn),當(dāng)最高兩位為31(即a=311),本次只對(duì)應(yīng)局部點(diǎn)00~56,共b+1次,所有點(diǎn)加起來(lái)共有(a%10*100)+(b+1),這些點(diǎn)百位對(duì)應(yīng)為1
4、當(dāng)i表示百位,且百位對(duì)應(yīng)的數(shù)為0,如n=31056,i=100,則a=310,b=56,此時(shí)百位為1的次數(shù)有a/10=31(最高兩位0~30)
5、綜合以上三種情況,當(dāng)百位對(duì)應(yīng)0或>=2時(shí),有(a+8)/10次包含所有100個(gè)點(diǎn),還有當(dāng)百位為1(a%10==1),需要增加局部點(diǎn)b+1
6、之所以補(bǔ)8,是因?yàn)楫?dāng)百位為0,則a/10==(a+8)/10,當(dāng)百位>=2,補(bǔ)8會(huì)產(chǎn)生進(jìn)位位,效果等同于(a/10+1)
# -*- coding:utf-8 -*- class Solution:def NumberOf1Between1AndN_Solution(self, n):# write code herei = 1count = 0while i <= n:a = n / ib = n % icount = count + (a+8)/10*i + (a%10==1)*(b+1)i *= 10return count32、把數(shù)組排成最小的數(shù)
輸入一個(gè)正整數(shù)數(shù)組,把數(shù)組里所有數(shù)字拼接起來(lái)排成一個(gè)數(shù),打印能拼接出的所有數(shù)字中最小的一個(gè)。例如輸入數(shù)組{3,32,321},則打印出這三個(gè)數(shù)字能排成的最小數(shù)字為321323。
解答:
方法:比較字符串s1和s2大小時(shí),即比較s1+s2和s2+s1的大小,小的放在前面,比較某一位的字符時(shí),需要將這個(gè)位置和其后面所有位置的字符串進(jìn)行比較。時(shí)間復(fù)雜度為O(n^2),注意兩點(diǎn):1、數(shù)組為空時(shí)要返回‘’;2、數(shù)組中全為0時(shí),返回的是0,而不是00000.
# -*- coding:utf-8 -*- class Solution:def PrintMinNumber(self, numbers):# write code hereif numbers == []:return ''for i in range(len(numbers)):for j in range(i+1,len(numbers)):tmp0 = int(str(numbers[i]) + str(numbers[j]))tmp1 = int(str(numbers[j]) + str(numbers[i]))if tmp0 > tmp1:numbers[i],numbers[j] = numbers[j],numbers[i]res = ''for i in numbers:res += str(i)if int(res) == 0:return 0else:return res33、丑數(shù)
把只包含質(zhì)因子2、3和5的數(shù)稱作丑數(shù)(Ugly Number)。例如6、8都是丑數(shù),但14不是,因?yàn)樗|(zhì)因子7。 習(xí)慣上我們把1當(dāng)做是第一個(gè)丑數(shù)。求按從小到大的順序的第N個(gè)丑數(shù)。
解答:
方法1:暴力求解,任何丑數(shù)p,2p,3p,5p結(jié)果仍是偶數(shù),1是最小的丑數(shù),從1開(kāi)始,將12,13,15比較,得到的最小丑數(shù)2,將得到的丑數(shù)2也同樣2,3,*5,比較最小的數(shù)
# -*- coding:utf-8 -*- class Solution:def GetUglyNumber_Solution(self, index):# write code hereif index < 7:return indexres = [0] * indexres[0] = 1tmp2 = 0tmp3 = 0tmp5 = 0for i in range(1,index):res[i] = min(res[tmp2]*2,res[tmp3]*3,res[tmp5]*5)if res[i] == res[tmp2]*2:tmp2 += 1if res[i] == res[tmp3]*3:tmp3 += 1if res[i] == res[tmp5]*5:tmp5 += 1return res[-1]34、第一個(gè)只出現(xiàn)一次的字符
在一個(gè)字符串(0<=字符串長(zhǎng)度<=10000,全部由字母組成)中找到第一個(gè)只出現(xiàn)一次的字符,并返回它的位置, 如果沒(méi)有則返回 -1(需要區(qū)分大小寫(xiě)).
解答:
# -*- coding:utf-8 -*- class Solution:def FirstNotRepeatingChar(self, s):# write code hereres_dict = {}for i in range(len(s)):if s[i] not in res_dict:res_dict[s[i]] = 0res_dict[s[i]] += 1for i in range(len(s)):if res_dict[s[i]] == 1:return ireturn -135、數(shù)組中的逆序?qū)?/h1>
在數(shù)組中的兩個(gè)數(shù)字,如果前面一個(gè)數(shù)字大于后面的數(shù)字,則這兩個(gè)數(shù)字組成一個(gè)逆序?qū)?。輸入一個(gè)數(shù)組,求出這個(gè)數(shù)組中的逆序?qū)Φ目倲?shù)P。并將P對(duì)1000000007取模的結(jié)果輸出。 即輸出P%1000000007
解答:
方法:歸并排序,在合并時(shí),當(dāng)前面的數(shù)組值array[i]大于后面數(shù)組值array[j]時(shí),則前面
數(shù)組array[i]~array[mid]都是大于array[j]的,count += mid+1 - i
# -*- coding:utf-8 -*- class Solution:def __init__(self):self.count = 0def InversePairs(self, data):if len(data) == 0:return 0# write code hereself.MergeSort(data,0,len(data)-1)return self.count%1000000007def MergeSort(self,array,low,high):if low < high:mid = (low + high) >> 1self.MergeSort(array,low,mid)self.MergeSort(array,mid+1,high)self.count += self.MergeArray(array,low,mid,high) ?def MergeArray(self,array,low,mid,high):i = lowj = mid + 1tmp = []count = 0while i <= mid and j <= high:if array[i] < array[j]:tmp.append(array[i])i += 1else:tmp.append(array[j])j += 1count += mid - i + 1while i <= mid:tmp.append(array[i])i += 1while j <= high:tmp.append(array[j])j += 1for k in range(len(tmp)):array[low + k] = tmp[k]return count36、兩個(gè)鏈表的第一個(gè)公共結(jié)點(diǎn)
輸入兩個(gè)鏈表,找出它們的第一個(gè)公共結(jié)點(diǎn)。
解答:
方法1:
長(zhǎng)度相同有公共結(jié)點(diǎn),第一次就遍歷到;沒(méi)有公共結(jié)點(diǎn),走到尾部NULL相遇,返回NULL? 長(zhǎng)度不同有公共結(jié)點(diǎn),第一遍差值就出來(lái)了,第二遍一起到公共結(jié)點(diǎn);沒(méi)有公共,一起到結(jié)尾NULL。
方法2:
遍歷兩個(gè)鏈表,如果鏈表長(zhǎng)度相同,找到第一個(gè)相同的結(jié)點(diǎn);不相同時(shí),先將長(zhǎng)的鏈表移動(dòng)到和短的鏈表相同長(zhǎng)度的位置,然后找到第一個(gè)相同的結(jié)點(diǎn)
# -*- coding:utf-8 -*- # class ListNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.next = None class Solution:def FindFirstCommonNode(self, pHead1, pHead2):# write code herep1 = pHead1p2 = pHead2while p1 != p2:if not p1:p1 = pHead2else:p1 = p1.nextif not p2:p2 = pHead1else:p2 = p2.nextreturn p1def FindFirstCommonNode(self, pHead1, pHead2):# write code heresum1 = self.get_length(pHead1)sum2 = self.get_length(pHead2)if sum1 > sum2:pHead1 = self.get_equal(pHead1,sum1-sum2)else:pHead2 = self.get_equal(pHead2,sum2-sum1)while pHead1 != pHead2:pHead1 = pHead1.nextpHead2 = pHead2.nextreturn pHead1def get_equal(self,pHead,s):while s > 0:pHead = pHead.nexts -= 1return pHeaddef get_length(self,pHead):summ = 0while pHead:pHead = pHead.nextsumm += 1return summ37、數(shù)字在排序數(shù)組中出現(xiàn)的次數(shù)
統(tǒng)計(jì)一個(gè)數(shù)字在排序數(shù)組中出現(xiàn)的次數(shù)
解答:
方法1:
排序數(shù)組是升序排列,且數(shù)組中的數(shù)都是整數(shù),則可以使用tmp0 = k – 0.5 和tmp1 = k + 0.5兩個(gè)數(shù),這兩個(gè)數(shù)在數(shù)組中都沒(méi)有,但可以找到第一個(gè)大于tmp0和tmp1的數(shù)的index,相減就是最后k出現(xiàn)的次數(shù)
方法2:
如果數(shù)組中的數(shù)不是整數(shù),則利用二分法找到k值的第一次出現(xiàn)的index和最后一次出現(xiàn)的index;注意考慮沒(méi)有k值的情況。
# -*- coding:utf-8 -*- class Solution:def GetNumberOfK(self, data, k):tmp0 = k - 0.5tmp1 = k + 0.5count = self.get_index(data,tmp1) - self.get_index(data,tmp0)return count ?def get_index(self,data,k):begin = 0end = len(data) - 1while begin <= end:mid = (begin + end) >> 1if data[mid] < k:begin = mid + 1elif data[mid] > k :end = mid - 1return beginclass Solution:def GetNumberOfK(self, data, k):tmp0 = self.get_first(data,k,0,len(data)-1)tmp1 = self.get_last(data, k, 0, len(data) - 1)if tmp0 != -1 and tmp1 != -1:return tmp1 - tmp0 + 1return 0 ? ?def get_first(self,data,k,begin,end):if begin > end:return -1mid = (begin + end) >> 1if data[mid] > k:return self.get_first(data,k,begin,mid-1)elif data[mid] < k:return self.get_first(data,k,mid+1,end)elif mid - 1 >= begin and data[mid-1] == k:return self.get_first(data,k,begin,mid-1)else:return mid ?def get_last(self,data,k,begin,end):while begin <= end:mid = (begin + end) >> 1if data[mid] > k:end = mid - 1elif data[mid] < k:begin = mid + 1elif mid + 1 <= end and data[mid+1] == k:begin = mid + 1else:return midreturn -1 ??
38、 二叉樹(shù)的深度
輸入一棵二叉樹(shù),求該樹(shù)的深度。從根結(jié)點(diǎn)到葉結(jié)點(diǎn)依次經(jīng)過(guò)的結(jié)點(diǎn)(含根、葉結(jié)點(diǎn))形成樹(shù)的一條路徑,最長(zhǎng)路徑的長(zhǎng)度為樹(shù)的深度。
解答:
方法1:
遞歸,遞歸實(shí)際也是深度優(yōu)先的思想(DFS),時(shí)間復(fù)雜度為O(lgN),但是空間復(fù)雜度最壞為O(N),當(dāng)二叉樹(shù)退化為鏈表的時(shí)候。
方法2:
非遞歸,廣度優(yōu)先遍歷BFS,時(shí)間復(fù)雜度O(N);利用兩個(gè)輔助值sum_count和count;sum_count記錄每層的結(jié)點(diǎn)個(gè)數(shù),當(dāng)count == sum_count時(shí)說(shuō)明一層的結(jié)點(diǎn)都已經(jīng)遍歷完畢,depth+1
# -*- coding:utf-8 -*- # class TreeNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.left = None # ? ? ? ? self.right = None class Solution:def TreeDepth(self, pRoot):if not pRoot:return 0left = int(self.TreeDepth(pRoot.left))right = int(self.TreeDepth(pRoot.right))return max(left,right)+1def TreeDepth(self, pRoot):# write code hereif not pRoot:return 0stack = []stack.append(pRoot)sum_count = 1count = 0depth = 0while stack:node = stack.pop(0)count += 1if node.left:stack.append(node.left)if node.right:stack.append(node.right)if count == sum_count:count = 0sum_count = len(stack)depth += 1return depth39、平衡二叉樹(shù)
輸入一棵二叉樹(shù),判斷該二叉樹(shù)是否是平衡二叉樹(shù)。
解答:
方法1:遞歸法
有了求二叉樹(shù)的深度的經(jīng)驗(yàn)之后,很容易想到一個(gè)思路:遍歷每個(gè)結(jié)點(diǎn)的時(shí)候,得到它的左右結(jié)點(diǎn)的深度。如果每個(gè)結(jié)點(diǎn)的左右二叉樹(shù)的深度相差都不超過(guò)1,就是平衡二叉樹(shù)。
但是這個(gè)方法每個(gè)結(jié)點(diǎn)都被重復(fù)遍歷,效率不高
方法2:自底向上
如果我們用后序遍歷的方式遍歷二叉樹(shù)的每一個(gè)結(jié)點(diǎn),在遍歷到一個(gè)結(jié)點(diǎn)之前我們就已經(jīng)遍歷了它的左右子樹(shù)。只要在遍歷每個(gè)結(jié)點(diǎn)的時(shí)候幾下它的深度,就可以一次遍歷判斷每個(gè)結(jié)點(diǎn)是不是平衡二叉樹(shù)。
# -*- coding:utf-8 -*- # class TreeNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.left = None # ? ? ? ? self.right = None class Solution:def IsBalanced_Solution(self, pRoot):depth = self.get_depth(pRoot)if depth == -1:return Falsereturn Truedef get_depth(self,pRoot):if not pRoot:return 0left = self.get_depth(pRoot.left)if left == -1:return -1right = self.get_depth(pRoot.right)if right == -1:return -1if abs(left-right) <= 1:return max(left,right) + 1else:return -1def IsBalanced_Solution(self, pRoot):# write code hereif not pRoot:return Trueleft = self.get_depth(pRoot.left)right = self.get_depth(pRoot.right)return abs(left - right) <= 1 and self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right) ?def get_depth(self, pRoot):if not pRoot:return 0return max(self.get_depth(pRoot.left), self.get_depth(pRoot.right)) + 140、 數(shù)組中只出現(xiàn)一次的數(shù)字
一個(gè)整型數(shù)組里除了兩個(gè)數(shù)字之外,其他的數(shù)字都出現(xiàn)了兩次。請(qǐng)寫(xiě)程序找出這兩個(gè)只出現(xiàn)一次的數(shù)字。
解答:
方法:
1、考慮數(shù)組中只有一個(gè)數(shù)只出現(xiàn)一次,則將所有數(shù)字異或就可以得到這個(gè)數(shù)。
2、兩個(gè)數(shù)不一樣,則異或的結(jié)果至少有一位為1,我們找到第一個(gè)為1的位置,記作n;
找到數(shù)字k第一個(gè)為1的位
3、根據(jù)第n為是否為1的標(biāo)準(zhǔn)可以將數(shù)組分為2個(gè)部分,這兩個(gè)只出現(xiàn)一次的數(shù)就分別在這兩個(gè)部分中,在通過(guò)異或即可得到結(jié)果
# -*- coding:utf-8 -*- class Solution:# 返回[a,b] 其中ab是出現(xiàn)一次的兩個(gè)數(shù)字def FindNumsAppearOnce(self, array):# write code hereres = 0for i in array:res ^= iindex = self.get_index(res)num0 = num1 = 0for i in array:if self.get_sep(i,index) == 0:num0 ^= ielse:num1 ^= ireturn num0,num1 ?def get_index(self,k):index = 0while k & 1 == 0:k = k >> 1index += 1return indexdef get_sep(self,k,index):k = k >> indexreturn k & 1總結(jié)
以上是生活随笔為你收集整理的牛客网剑指offer编程实践31-40题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 牛客网剑指offer编程实践21-30题
- 下一篇: 牛客网剑指offer编程实践41-50题