这不算算法,主要是一种思维方式。通过将现实问题转换为计算机进行推导的问题。
连号区间数(原题链接)
该题很典型的可以通过枚举进行,我们首先固定左顶点,然后遍历右顶点,逐渐判断最大值-最小值==l-r(为啥不用+1,自己领会)。
代码如下:
n=int(input())
cnt=0
list_=list(map(int,input().split(' ')))
for i in range(len(list_)):
max_=list_[i]
min_=list_[i]
for j in range(i,len(list_)):#本身也是一个结果
if max_<list_[j]:max_=list_[j]
if min_>list_[j]:min_=list_[j]
if max_-min_==j-i:
cnt+=1
#print(list_[i],list_[j])
print(cnt)
递增三元组(原题链接)
二分查找+排序即可
代码如下:
def get_low(x):
l=-1
r=n
while l+1!=r:
mid=l+r>>1
if a_lst[mid]<x:
l=mid
else:
r=mid
return l+1
def get_up(x):
l=-1
r=n
while l+1!=r:
mid=l+r>>1
if c_lst[mid]>x:
r=mid
else:
l=mid
return n-r
n=int(input())
a_lst=sorted(list(map(int,input().split())))
b_lst=sorted(list(map(int,input().split())))
c_lst=sorted(list(map(int,input().split())))
res=0
for x in b_lst:
#print(get_up(x))
res+=get_low(x)*get_up(x)
print(res)
另一种为前缀和做法。
n=int(input())
a_list=list(map(int,input().split(' ')))
b_list=list(map(int,input().split(' ')))
c_list=list(map(int,input().split(' ')))
res=0
ant=[0 for i in range(100001)]
cnt=[0 for i in range(100001)]
as_=[0 for i in range(100001)]
cs_=[0 for i in range(100001)]
for i in range(n):
ant[a_list[i]]+=1
cnt[c_list[i]]+=1
as_[0]=ant[0]
cs_[0]=cnt[0]
for i in range(1,100001):
as_[i]=ant[i]+as_[i-1]
cs_[i]=cnt[i]+cs_[i-1]
for b in b_list:
if b==0:
pass
else:
res+=as_[b-1]*(n-cs_[b])
print(res)
#采取前缀和需要特判b-1,若b小于0,则变为了-1,就错了!!!
特别数的和(原题链接)
代码如下:
n=int(input())
sum_=0
def check(i):
while i:
t=i%10
i//=10
if t==2 or t==0 or t==1 or t==9:
return True
return False
for i in range(1,n+1):
if check(i):
sum_+=i
print(sum_)
错误票据(原题链接)
通过构造出现次数数组来计算,枚举。
代码如下:
n=int(input())
t=n
cnt=[0 for _ in range(100001)]
max_=0
min_=100000
while t:
a_list=list(map(int,input().split(' ')))
for a in a_list:
cnt[a]+=1
max_=max(max_,a)
min_=min(min_,a)
t-=1
for i in range(min_,max_+1):
if cnt[i]==0:
m=i
if cnt[i]==2:
n=i
print('%d %d'%(m,n))
通过快排来进行推导也不错(需要注意remove的使用以及列表中in的使用)
n=int(input())
c=0
L=[]
while c<n:
s=input().split()
for i in s:
L.append(int(i))
c+=1
L.sort()
for i in range(L[0],L[-1]+1):
if i in L:
L.remove(i)
if i in L:
n=i
else:
m=i
print('%d %d'%(m,n))
使用collections模块的counter
import collections
n=int(input())
nums=[]
for i in range(n):
nums+=list(map(int,input().split(' ')))
counter=collections.Counter(nums)
#python中的counter容器
#记录其中出现次数最多的,这里就是重复出现的
rep=counter.most_common(1)[0][0]
nums.remove(rep)
los=(max(nums)+1-min(nums))*(max(nums)+min(nums))/2-sum(nums)
print('%d %d'%(rep,los))
回文日期(原题链接)
我们可以check前四位数字,然后填充后四位,判断其是否是合法日期且是否在范围内即可
代码如下:
start_data=int(input())
end_data=int(input())
cnt=0
mouth_list=[31,28,31,30,31,30,31,31,30,31,30,31]
def check(i):
year=i
mouth=(i%10)*10+(i//10)%10
day=((i//100)%10)*10+i//1000
num=year*10000+mouth*100+day
#print('%d %d %d'%(year,mouth,day))
if (year==0)|(day==0)|(mouth==0):
return False
if ((year%4==0)&(year%100!=0))|(year%400==0):
#闰年
if mouth==2:
if day<30:
if num>=start_data&num<=end_data:
return True
else:
if mouth<13:
if day<=mouth_list[mouth-1]:
if num>=start_data&num<=end_data:
return True
else:
if mouth<13:
if day<=mouth_list[mouth-1]:
if (num>=start_data)&(num<=end_data):
return True
return False
start=start_data//10000
end=end_data//10000
for i in range(start,end+1):
if check(i):
cnt+=1
print(cnt)
移动距离(原题链接)
看代码即可,蛇形移动问题。
代码如下:
w,m,n=map(int,input().split())
def get_pos(x):
x-=1
i=x//w
if i%2:
j=x%w
else:
j=w-1-x%w
return i,j
i1,j1=get_pos(m)
i2,j2=get_pos(n)
print(abs(i1-i2)+abs(j1-j2))
日期问题(原题链接)
看代码自行理解
代码如下:
def check(yy,mm,dd):
mouth_lst=[31,28,31,30,31,30,31,31,30,31,30,31]
if yy>=60:
yy+=1900
else:
yy+=2000
if yy%400==0 or (yy%100!=0 and yy%4==0):
mouth_lst[1]=29
if mm>0 and mm<13:
if 0<dd<=mouth_lst[mm-1]:
return yy*10000+mm*100+dd
return 0
aa,bb,cc=map(int,input().split('/'))
res=[]
if check(aa,bb,cc)!=0:
res.append(check(aa,bb,cc))
if check(cc,aa,bb)!=0:
res.append(check(cc,aa,bb))
if check(cc,bb,aa)!=0:
res.append(check(cc,bb,aa))
res=set(res)
res.sort()
for i in res:
print('%d-%02d-%02d'%(i//10000,(i//100)%100,i%100))
航班问题(原题链接)
学学别人漂亮的代码,思维碾压。需要注意的是,时差可以来回两次抵消掉了。同时我们可以注意,我们可以先统一为秒制,方便计算。
代码如下:
t=int(input())
for _ in range(t):
ans=0
for __ in range(2):
a=input().split()
for i in range(len(a)):
if i==2:ans+=int(a[i][2])*24*3600
else:
b=list(map(int,a[i].split(':')))
ans+=pow(-1,i+1)*(b[0]*3600+b[1]*60+b[2])
print(format("%02d:%02d:%02d"%( ans//7200, ans%(7200)//120, ans%120//2 ) ) )
#漂亮简洁,学着点
外卖店优先级(原题链接
该题主要采取模拟的方式来进行,需要注意对于边界的考虑以及何时出优先队列,需要考虑清楚。
代码如下:
n,m,t=map(int,input().split())
shop_dict={}
cnt=0
for _ in range(m):
t_,id=map(int,input().split())
if id in shop_dict:
shop_dict[id].append(t_)
else:
shop_dict.setdefault(id,[t_])
for _,tic_lst in shop_dict.items():
if len(tic_lst)<3:
continue
flag=0
score=2
tic_lst.sort()
for i in range(1,len(tic_lst)):
if tic_lst[i]!=tic_lst[i-1]:
score-=tic_lst[i]-tic_lst[i-1]-1
if score<0:
score=0
if score<=3:
flag=0
score+=2
if score>5:
flag=1
if flag and score-(t-tic_lst[-1])>3:
cnt+=1
print(cnt)
另一种解法:
[n,m,t]=list(map(int,input().split(' ')))
cnt=0
flag=False
T=m
tic_list=[]
score=2
while T:
tic_list.append(list(map(int,input().split()))[::-1])
T-=1
#按照店铺排序
tic_list.sort()#默认是升序的
tic_list.append([0,0])
for i in range(1,m+1):
if tic_list[i][0]!=tic_list[i-1][0]:#不是同一个商家
#此时就需要计算上一个商家是否在优先缓存中了
if flag and (score-(t-tic_list[i-1][1])>3):cnt+=1
flag=False
score=2#恢复原状
else:
#同一个商家,更新score并且判断是否在内
if tic_list[i][1]!=tic_list[i-1][1]:
score-=tic_list[i][1]-tic_list[i-1][1]-1
if score<0:score=0
if score<=3:flag=False
score+=2
if score>5:flag=True
print(cnt)
逆序对的数量(原题链接)
该题主要在于灵活运用归并排序的思维进行计算。
计算逆序对的数量(序列):
- 递归算左边的;
- 递归算右边的;
- 算一个左一个右的;
- 把他们加到到一起。
代码如下:
def merge_sort(nums):
if len(nums)<=1:return 0
mid=len(nums)//2
L=nums[:mid]
R=nums[mid:]
ans=merge_sort(L)+merge_sort(R)
#归并的过程
i=j=k=0
while i<len(L) and j<len(R):
if L[i]<=R[j]:
nums[k]=L[i]
k+=1
i+=1
else:
nums[k]=R[j]
ans+=len(L)-i
k+=1
j+=1
while i <len(L):
nums[k]=L[i]
k+=1
i+=1
while j <len(R):
nums[k]=R[j]
k+=1
j+=1
return ans
if __name__ == "__main__":
n = int(input())
nums = list(map(int, input().split()))
print(merge_sort(nums))
男的一批。要灵活运用python各种自带模块,同时需要关注各种排序算法的使用,以及各种思维的运用,如何简化问题。