输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
完全参考:https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/mian-shi-ti-43-1n-zheng-shu-zhong-1-chu-xian-de-2/
分请情况讨论某一位中1出现次数的计算方法。
class Solution(object):
def countDigitOne(self, n):
"""
:type n: int
:rtype: int
"""
digit,res=1,0
high,cur,low=n//10,n%10,0
while(high!=0 or cur!=0):
if cur==0:
res+=high*digit
elif cur==1:
res+=high*digit+low+1
else:
res+=(high+1)*digit
low+=cur*digit
cur=high%10
high=high//10
digit*=10
return res
数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。
思路:寻找n 与对应数字的关系,应该有对应的公式规律。
数字:num=123
数字中一位数的数量:n=3
一个数字的位数:digit,123为3位数,dight=3
digit 位数的起始数字:1,10,100,记为start
数字范围 s t a r t − e n d start-end start−end以上三个量的递推公式为:
digit=digit+1
start=start10
count=9start*dight
求解可以分为三步:
1.确定n所在的数字的位数,记为digit
2.确定n所在的数字,记为num
3.确定n是num中的哪一位,并返回结果
class Solution(object):
def findNthDigit(self, n):
"""
:type n: int
:rtype: int
"""
digit,start,count=1,1,9
# 1.计算n所在的位数区间[1-9]是一位数一共9个,[10,99]两位数一共90个
while(n>count):
n-=count
start*=10
digit+=1
count=9*start*digit
# 计算在该开始区间内所对应的数字
num=start+(n-1)//digit
# 确定是数字的哪一位
index=(n-1)%digit
return int(str(num)[index])
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
问题:能拼接的数字很多么?找最小的一个
[10,2] 可以拼接成102,210,明显102最小
本质是一个排序问题:排序的目的是使得量级最小的数字排在最前面,使得最后按顺序拼接的时候,拼接的数字最小.
10,5两个数字谁在前?按位数来比较,如果放了5,组成的3位数以5开头,所以不能放5,所以应该先放10
总之就是按位排序,谁小谁先放(数字左对齐比较,看看谁小,先比的数字对比较结果起决定性作用)
比如30和3,30的量级比3小,30应该在3前面。将数字转换成字符串,拼接后比较:(“30”+“3”=“303”)<(“3”+“30”)=>“30”<“3”
改造快排排序规则:
class Solution(object):
def minNumber(self, nums):
"""
:type nums: List[int]
:rtype: str
"""
def quick_sort_str(l,r,data):
if l<r:
p=patition(l,r,data)
quick_sort_str(l,p-1,data)
quick_sort_str(p+1,r,data)
def patition(i,j,data):
pivort=data[i]
while(i<j):
while(i<j and data[j]+pivort>pivort+data[j]): # 比较规则需要修改
j-=1
data[i]=data[j]
while(i<j and data[i]+pivort<=pivort+data[i]):
i+=1
data[j]=data[i]
data[i]=pivort
return i
nums_str=[]
for val in nums:
nums_str.append(str(val))
quick_sort_str(0,len(nums_str)-1,nums_str)
res=""
for char in nums_str:
res+=char
return res
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
dp[i] 表示nums[0]-nums[i-1] 能够翻译成的数字总数
dp 由前面的状态推导后面的状态。
这题有点类似与爬楼梯
class Solution(object):
def translateNum(self, num):
"""
:type num: int
:rtype: int
"""
num_lis=[]
while(num):
num_lis.append(num%10)
num//=10
num_lis.reverse()
n=len(num_lis)
if n<2:
return 1
dp=[0]*(n+1)
dp[0]=1
dp[1]=1
for i in range(2,n+1):
val=10*num_lis[i-2]+ num_lis[i-1] # 此位置和下一位置构成的数字[0,9],[10,15],[25,99]
if 0<=val<10 or 26<=val<=99: # 09,26, nums[i]自己翻译,只有一种翻译方式
dp[i]=dp[i-1]
if 10<=val <26: # num=12, 2自己单独翻译,12一起翻译,
dp[i]=dp[i-1]+dp[i-2]
return dp[-1]
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
递归所有的路径,时间超出限制(20/61)。最值问题,应该有最有子结构。
class Solution(object):
def __init__(self):
self.res=0
def maxValue(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
m=len(grid)
n=len(grid[0])
def dfs(i,j,val):
if i>=m or j>=n:
return
val+=grid[i][j]
if i==m-1 and j==n-1:
self.res=max(self.res,val)
return # 要不要return 呢
dfs(i+1,j,val)
dfs(i,j+1,val)
dfs(0,0,0)
return self.res
动态规划解题:dp[i][j]到单元格(i,j) 的最大价值。
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
滑动窗口法:[l,r] 中有一个hash表,统计每个字符的个数,当存在时,窗口变小,直至个数减为1.
再移动右端。
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
win={}
left,right=0,0
res=0
m=len(s)
while(right<m):
c1=s[right]
if win.get(c1)==None:
win[c1]=1
else:
win[c1]+=1
right+=1
while(win[c1]>1):
c2=s[left]
win[c2]-=1
left+=1
res=max(res,right-left) # 上面right+ 了1,所以直接减去
return res
我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。(质因子:因子是质数)
说明:
1 是丑数。
n 不超过1690。
思路:丑数的递归性质,丑数只包含质因子2,3,5,因此 丑数=某较小的丑数*某因子
暴力解法:时间超出限制404/595
class Solution(object):
def nthUglyNumber(self, n):
"""
:type n: int
:rtype: int
"""
i=1
num=1
isun_hash={1:True,2:True,3:True,5:True}
def is_UN(num):
for val in [2,3,5]:
if num%val==0 and isun_hash.get(num//val):
return True
return False
while(i<n):
num+=1
if is_UN(num) :
isun_hash[num]=True
i+=1
# print(i,num)
return num
动态规划: 设动态规划列表 dp ,dp[i]代表第 i + 1个丑数。
利用状态更新求解dp[n-1] 即可。
用a,b,c 三个索引指向num[a]*2,nums[b]*3,nums[c]*5第一次超过dp[i-1]索引,dp[i] 就更新为最小的那个数。将a,b,c初始化为0,0,0,依次填充dp 序列
class Solution(object):
def nthUglyNumber(self, n):
"""
:type n: int
:rtype: int
"""
dp=[1]*n
a,b,c=0,0,0
for i in range(1,n):
n2,n3,n5=dp[a]*2,dp[b]*3,dp[c]*5
dp[i]=min(n2,n3,n5)
if dp[i]==n2: # 只能用if ,n2,n3,n5可能会相等,这时需要同时更新下标
a+=1
if dp[i]==n3:
b+=1
if dp[i]==n5:
c+=1
return dp[-1]
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
class Solution(object):
def firstUniqChar(self, s):
"""
:type s: str
:rtype: str
"""
win_hash={}
for char in s:
if win_hash.get(char)==None:
win_hash[char]=1
else:
win_hash[char]+=1
for char in s: # 重新遍历一遍,使得返回的字符是最左边第一个出现的字符串
if win_hash.get(char)==1:
return char
return " "
输入两个链表,找出它们的第一个公共节点。
双指针技巧
注意点:先判断两个链表是否相交,如果相交,在寻找交点
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if headA==None or headB==None:
return None
pa,pb=headA,headB
while(pa.next):
pa=pa.next
while(pb.next):
pb=pb.next
if pa!=pb:
return None
else:
pa,pb=headA,headB
while(pa!=pb):
if pa.next:
pa=pa.next
else:
pa=headB
if pb.next:
pb=pb.next
else:
pb=headA
return pa
统计一个数字在排序数组中出现的次数。
暴力求解:通过了!!
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
res=0
for num in nums:
if num==target:
res+=1
return res
大佬说还可以用二分法做。
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
[0,1,3],n=4,l=4-1=3,数字范围[0,3] 一共n 中情况.
缺失数字的左边:nums[i]==i
缺失数字的位置上:nums[i]!=i
暴力:
class Solution(object):
def missingNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
l=len(nums)
for i in range(l):
if nums[i]!=i:
return i
return l
二分查找:
class Solution(object):
def missingNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
l=len(nums)
i,j=0,l-1
while(i<=j): # 搜索到i>j的那个点就缺失点
mid=(i+j)//2
if nums[mid]==mid:
i=mid+1 # 左边没有缺失
else:
j=mid-1 # 缺失已经发生,在左半段
return i