题目描述
小Q正在给一条长度为n的道路设计路灯安置方案。
为了让问题更简单,小Q把道路视为n个方格,需要照亮的地方用’.'表示, 不需要照亮的障碍物格子用’X’表示。
小Q现在要在道路上设置一些路灯, 对于安置在pos位置的路灯, 这盏路灯可以照亮pos - 1, pos, pos + 1这三个位置。
小Q希望能安置尽量少的路灯照亮所有’.'区域, 希望你能帮他计算一下最少需要多少盏路灯。
输入描述:
输入的第一行包含一个正整数t(1 <= t <= 1000), 表示测试用例数
接下来每两行一个测试数据, 第一行一个正整数n(1 <= n <= 1000),表示道路的长度。
第二行一个字符串s表示道路的构造,只包含’.‘和’X’。
输出描述:
对于每个测试用例, 输出一个正整数表示最少需要多少盏路灯。
示例1
输入
2
3
.X.
11
…XX…XX
输出
1
3
解法
比较简单的贪心算法,判断好边界条件即可
t = int(input().strip())
for _ in range(t):
n = int(input().strip())
s = input().strip()
res = 0
flag = 0
for i in range(n):
if flag == 0 and s[i] == '.':
if i == n - 1:
res += 1
else:
flag = 1
elif flag == 1:
res += 1
flag = 2
elif flag == 2:
flag = 0
print(res)
题目描述
众所周知,牛妹非常喜欢吃蛋糕。
第一天牛妹吃掉蛋糕总数三分之一多一个,第二天又将剩下的蛋糕吃掉三分之一多一个,以后每天吃掉前一天剩下的三分之一多一个,到第n天准备吃的时候只剩下一个蛋糕。
牛妹想知道第一天开始吃的时候蛋糕一共有多少呢?
示例1
输入
2
输出
3
示例2
输入
4
输出
10
备注: 解法 题目描述 示例1 备注: 解法 题目描述 示例1 备注: 解法 题目描述 示例1 示例2 备注: 解法 题目描述 那么问题来了,在最优的情况下,他俩手中得到的礼物价值和的最小差值是多少呢? 示例1 示例2 备注: 解法 题目描述 示例1 示例2 备注: 解法 题目描述 示例1 示例2 备注: 题目描述 解法 题目描述 解法 题目描述 解法 另一种题目问法: 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 思路:(斐波拉契数列) 当只有一级台阶时(n=1),此时青蛙跳一次就可以完成目标;当只有两级台阶时(n=2),青蛙可以一次跳一级台阶分两次完成也可以一次跳两级台阶,此时有两种跳法使得青蛙可以达成目标; 当n>2时,此时我们可以把n级台阶的跳法看成是n的函数:f(n);如果青蛙第一步跳一级台阶,之后的跳法数目就是之后剩余n-1级台阶的跳法数目,即f(n-1);另一种可能的情况就是青蛙第一步跳两级台阶,之后的跳法数目就是之后剩余的n-2级台阶的跳法数目;所以n级台阶的不同跳法的总数是f(n)=f(n-1)+f(n-2) 题目描述 解法 其实就是用二进制来模拟加法操作。首先将两个数最低位相加,如果都是 1,那么就得到0,并且进位1,然后接着算下一位。 但是这样一位一位模拟不方便实现,更简单的实现方法是直接把两个数对应位相加,不管进位。然后进位单独计算,如果某一位两个数都是1,那么进位就会对下一位产生影响。然后接着算不进位求和加上进位的值,再计算新的进位,依次重复下去,直到进位为0为止。 用一个实际的例子来演示一下,计算3+7的值,其中s表示每一步不考虑进位的求和,c表示每一步的进位,最后得到结果,也就是十进制的10 : 题目描述 题目描述 解法 题目描述 解法 题目描述 解法 我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 解法 题目描述 在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树 解法 方法2: 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 解法 输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的) 解法 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 保证base和exponent不同时为0 解法 首先做预处理:求pow(b, n),如果n为负数怎么解决
0
动态规划的思路,实际上反过来想,第一天是1,求第n天的总数。#
#
# @param n int整型 只剩下一只蛋糕的时候是在第n天发生的.
# @return int整型
#
class Solution:
def cakeNumber(self , n ):
# write code here
# x = y - (y / 3 + 1), y = (x + 1) * 3 / 2
res = 1
for i in range(n - 1):
res = int((res + 1) * 3 / 2)
return res
牛妹的礼物
众所周知,牛妹有很多很多粉丝,粉丝送了很多很多礼物给牛妹,牛妹的礼物摆满了地板。
地板是N\times MN×M的格子,每个格子有且只有一个礼物,牛妹已知每个礼物的体积。
地板的坐标是左上角(1,1) 右下角(N, M)。
牛妹只想要从屋子左上角走到右下角,每次走一步,每步只能向下走一步或者向右走一步或者向右下走一步
每次走过一个格子,拿起(并且必须拿上)这个格子上的礼物。
牛妹想知道,她能走到最后拿起的所有礼物体积最小和是多少?
输入
[[1,2,3],[2,3,4]]
输出
7
说明
(1,1)->(1,2)->(2,3)
0
动态规划#
#
# @param presentVolumn int整型二维数组 N*M的矩阵,每个元素是这个地板砖上的礼物体积
# @return int整型
#
class Solution:
def selectPresent(self , presentVolumn ):
# write code here
if not presentVolumn:
return 0
N, M = len(presentVolumn), len(presentVolumn[0])
dp = [[0 for i in range(M)] for j in range(N)]
for i in range(N):
for j in range(M):
if i > 0 and j > 0:
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + presentVolumn[i][j]
elif i > 0 :
dp[i][j] = dp[i - 1][j] + presentVolumn[i][j]
elif j > 0 :
dp[i][j] = dp[i][j - 1] + presentVolumn[i][j]
else:
dp[i][j] = presentVolumn[i][j]
return dp[N - 1][M - 1]
最大数
给定一个包含大写英文字母和数字的句子,找出这个句子所包含的最大的十六进制整数,返回这个整数的值。数据保证该整数在int表示范围内
输入
“012345BZ16”
输出
1193051
说明
12345B对应十进制为1193051
0<字符串长度<=105
不要用字符串进行大小的比较,直接转成数字来比,时间够#
#
# @param s string字符串
# @return int整型
#
class Solution:
def solve(self , s ):
# write code here
tmp = ""
res = 0
chars = [str(x) for x in range(10)] + ['A', 'B', 'C', 'D', 'E', 'F']
for i in range(len(s)):
if s[i] in chars:
tmp += s[i]
else:
if tmp != "":
res = max(res, self.c2int(tmp))
tmp = ""
return res
def c2int(self, res):
num = 0
for i in range(len(res)):
x = res[i]
if x in [str(x) for x in range(10)]:
x = int(x)
else:
x = 10 + (ord(x) - ord('A'))
num = num * 16 + x
return num
神奇的数字
在这个特殊的假期里,由于牛牛在家特别无聊,于是他发明了一个小游戏,游戏规则为:将字符串数字中为偶数位的数字进行翻转,将翻转后的结果进行输出。
输入
“1234”
输出
“1432”
说明
第2、4位为偶数,所以将其翻转后,得到 1432
输入
“12346”
输出
“16342”
说明
第2、4、5位为偶数,所以将其翻转后,得到 16342
数字的长度<=10^7 且不包含数字0
就是个双指针,一个从左往右,一个从右往左,遇到偶数就交换一下。#
#
# @param number string字符串
# @return string字符串
#
class Solution:
def change(self , number ):
# write code here
if not number or len(number) == 1:
return number
nums = [int(x) for x in number]
i, j = 0, len(nums) - 1
while i < j:
while i < j and nums[i] % 2 == 1:
i += 1
while i < j and nums[j] % 2 == 1:
j -= 1
nums[i], nums[j] = nums[j], nums[i]
i += 1
j -= 1
nums = [str(x) for x in nums]
return ''.join(nums)
牛能和牛可乐的礼物
众所周知,牛能和牛可乐经常收到小粉丝们送来的礼物,每个礼物有特定的价值,他俩想要尽可能按照自己所得价值来平均分配所有礼物。
p.s 礼物都很珍贵,所以不可以拆开算哦
输入
[1,2,3,4]
输出
0
说明
他俩一个人拿1,4 。另一个人拿2,3
输入
[1,3,5]
输出
1
说明
他俩一个人拿1,3.另一个人拿5
单个礼物价值不超过100,礼物个数小于100,所有礼物总价值不超过10000
01背包的变形:体积和价值都是题目中给的“礼物价值”。
把总体积的一半作为背包容量,挨个判断当前的礼物是否要放入到背包。最后背包中m体积所容纳的就是最多的礼物。#
#
# @param presentVec int整型一维数组 每个礼物的价值
# @return int整型
#
class Solution:
def maxPresent(self , presentVec ):
# write code here
n = len(presentVec)
m = int((sum(presentVec) + 1)/ 2)
dp = [0 for i in range(m + 1)]
for i in range(n):
for j in range(m, -1, -1):
if presentVec[i] > j:
continue
dp[j] = max(dp[j], dp[j - presentVec[i]] + presentVec[i])
a = dp[m]
b = sum(presentVec) - a
return abs(a - b)
牛妹的面试
众所周知,牛妹是一个offer收割姬,这次面试她遇到了这样的一个问题。
给了一个序列,让找出最长的“凸子序列”
何为“凸子序列”:数列中有一个xi,使得所有x0
eg:12345431,是山峰序列,12345234不是山峰序列
注:单调递增或单调递减序列也算山峰序列;单独一个数是长度为1的山峰序列
输入
[1,2,3,6,1]
输出
5
输入
[1,2,2,1]
输出
3
说明
1,2,1
给定的序列中数都大于0 且不超过10000,且序列长度不超过1000
开始想的是先求出列表中的最大值,那么从最大值的位置分开,左右两边分别得到最长递增序列的长度就可以了。后来发现这个会有很多边界问题,处理起来比较麻烦。
从网上发现,其实就从左到右,从右到左分别得到两个递增序列的dp数组,然后在每个位置分别相加,得到的就是山峰长度。#
# 返回最大山峰序列长度
# @param numberList int整型一维数组 给定的序列
# @return int整型
#
class Solution:
def mountainSequence(self , numberList ):
# write code here
if len(numberList) <= 1:
return len(numberList)
n = len(numberList)
res = 0
dp1 = self.dp_fuc(numberList)
dp2 = self.dp_fuc(numberList[::-1])
for i, x in enumerate(numberList):
tmp = dp1[i] + dp2[n - i - 1]
res = max(res, tmp)
return res - 1
def dp_fuc(self, sublist):
n = len(sublist)
if n == 0:
return 0
dp = [1] * n
for i in range(1, n):
for j in range(0, i):
if sublist[j] < sublist[i]:
dp[i] = max(dp[i], dp[j] + 1)
return dp
字符串距离计算
给定两个长度相等的,由小写字母组成的字符串S1和S2,定义S1和S2的距离为两个字符串有多少个位置上的字母不相等。
现在牛牛可以选定两个字母X1和X2,将S1中的所有字母X1均替换成X2。(X1和X2可以相同)
牛牛希望知道执行一次替换之后,两个字符串的距离最少为多少。
输入
“aaa”,“bbb”
输出
0
说明
牛牛可以将S1中的字符’a’全部替换成字符’b’,这样S1就变成了"bbb",那么S1和S2的距离就是0
输入
“aabb”,“cdef”
输出
3
说明
一种可行的方案是将S1中的字符’a’全部替换成字符’c’,那么S1变成了"ccbb",和S2的距离是3
解法
参考标准题解:
对于所有可能的X1, X2, 记录cnt[X1][X2]有多少个位置i, 使得S1[i] == X1, S2[i] == X2
这一步只需扫描一遍字符串即可计算得到
然后枚举可能的X1, X2,这时距离 = 原本的距离 + cnt[X1][X1] - cnt[X1][X2]
时间复杂度O(N)#
# 计算最少的距离
# @param S1 string字符串 第一个字符串
# @param S2 string字符串 第二个字符串
# @return int整型
#
class Solution:
def GetMinDistance(self , S1 , S2 ):
# write code here
cnt = [[0 for i in range(26)] for j in range(26)]
ans = 0
for i in range(len(S1)):
x, y = S1[i], S2[i]
xx, yy = ord(x) - ord('a'), ord(y) - ord('a')
cnt[xx][yy] += 1
if xx != yy:
ans += 1
res = ans
for i in range(26):
for j in range(26):
res = min(res, ans + cnt[i][i] - cnt[i][j])
return res
用两个栈实现队列
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
开始没怎么看明白题目,所以看了题解。栈A用来作入队列。栈B用来出队列,当栈B为空时,栈A全部出栈到栈B,栈B再出栈(即出队列)。这个想法还是比较巧妙的。# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, node):
# write code here
self.stack1.append(node)
def pop(self):
# return xx
if self.stack2 == []:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
其实就是用二分法。注意这里面数组中可能会存在重复的数字,所以会有另外一个情况。
# -*- coding:utf-8 -*-
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if len(rotateArray) == 0:
return 0
l, r = 0, len(rotateArray) - 1
while l <= r:
mid = (l + r) // 2
if rotateArray[mid - 1] > rotateArray[mid]:
return rotateArray[mid]
elif rotateArray[l] < rotateArray[mid]:
l = mid + 1
elif rotateArray[l] > rotateArray[mid]:
r = mid - 1
else:
l -= 1
r -= 1
变态跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
使用数学归纳法,台阶为n时,BT(n) = BT(n-1) + BT(n-2) + … + BT(1) + 1 = 2BT(n-1)
得到:当n>=1时,变态跳台阶的通式是:
BT(n) = 2BT(n-1) n>0# -*- coding:utf-8 -*-
class Solution:
def jumpFloorII(self, number):
# write code here
if number == 1:
return 1
return 2 * self.jumpFloorII(number - 1)
不用加减乘除做加法
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
参考:https://zhuanlan.zhihu.com/p/112407870
因为不允许采用四则运算,所以只能考虑位运算了。
# -*- 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 <= 0x7FFFFFFF else ~(num1 ^ 0xFFFFFFFF)
二叉树的镜像
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
解法
就直接递归的交换处理左右子树就可以# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if root == None:
return root
root.left, root.right = root.right, root.left
root.left = self.Mirror(root.left)
root.right = self.Mirror(root.right)
return root
构建乘积数组
给定一个数组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];)
其实就是提前准备好两个全乘好的数组,然后再从左到右过一遍A,得到对应位置上两个数组的乘积。# -*- coding:utf-8 -*-
class Solution:
def multiply(self, A):
# write code here
l, r = [], []
n = len(A)
tmp = 1
l.append(tmp)
for i, x in enumerate(A):
tmp *= x
l.append(tmp)
tmp = 1
for i in range(len(A)-1, -1, -1):
tmp *= A[i]
r.append(tmp)
r.append(1)
res = []
for i in range(len(A)):
tmp = l[i] * r[n - i - 2]
res.append(tmp)
return res
连续子数组的最大和
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
就是简单的动态规划# -*- coding:utf-8 -*-
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
dp = [0] * len(array)
for i, x in enumerate(array):
if i == 0:
dp[i] = x
ma = x
dp[i] = max(x, dp[i - 1] + x)
if dp[i] > ma:
ma = dp[i]
return ma
跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
就是斐波那契数列,但是如果直接递归会超时,所以迭代。# -*- coding:utf-8 -*-
class Solution:
def jumpFloor(self, number):
# write code here
res = []
for i in range(1, number + 1):
if i in [0, 1, 2]:
res.append(i)
else:
res.append(res[-1] + res[-2])
return res[-1]
'''
if number in [0, 1, 2]:
return number
return self.jumpFloor(number - 1) + self.jumpFloor(number - 2)
'''
矩形覆盖
和上面的题一样,不过这个要找规律,可以发现n=0, f=0; n=1, f=1; n=2, f=2; n=3, f=3; n=4; f=5… 就比如n=4的时候,其中3个可以在n=3的情况下加上一个竖着的,另外2个就是在n=2的情况下加上两个横着的。# -*- coding:utf-8 -*-
class Solution:
def rectCover(self, number):
# write code here
res = []
for i in range(0, number + 1):
if i in [0, 1, 2]:
res.append(i)
else:
res.append(res[-1] + res[-2])
return res[-1]
平衡二叉树
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在二叉搜索树那块也做过这个题,就是两个递归调用,一次是求深度,一次是求子树是否平衡。问题是求深度那个递归需要调用好几次,而且其中可能会有些重复计算。
所以可以用自底向上的方法来求,利用后序遍历:左子树、右子树、根节点,可以先递归到叶子节点,然后在回溯的过程中来判断是否满足条件。# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def depth(self, root):
if not root:
return 0
return max(self.depth(root.left), self.depth(root.right)) + 1
def IsBalanced_Solution(self, pRoot):
# write code here
if not pRoot:
return True
if abs(self.depth(pRoot.left) - self.depth(pRoot.right)) > 1:
return False
return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def depth(self, root):
if not root:
return 0
l = self.depth(root.left)
if l == -1:
return -1
r = self.depth(root.right)
if r == -1:
return -1
if abs(l - r) > 1:
return -1
return max(l, r) + 1
def IsBalanced_Solution(self, pRoot):
# write code here
if not pRoot:
return True
if self.depth(pRoot) == -1:
return False
return True
二进制中1的个数
第一种,可以将n上的每一位与1取与,统计1的个数;在求解的过程中每次循环时1左移一位,即n<<1
第二种,如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。# -*- coding:utf-8 -*-
class Solution:
def NumberOf1(self, n):
# write code here
if n < 0:
n = n & 0xffffffff
res = 0
while n != 0:
n = n & (n - 1)
res += 1
return res
两个链表的第一个公共节点
就是首先构造出相同长度的链表,这样的话就用双指针同时在两个链表遍历肯定会有公共节点了。# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
# write code here
l1, l2 = 0, 0
cur1 = pHead1
while cur1:
l1 += 1
cur1 = cur1.next
cur2 = pHead2
while cur2:
l2 += 1
cur2 = cur2.next
tmp = abs(l1 - l2)
if l1 > l2:
while tmp > 0:
pHead1 = pHead1.next
tmp -= 1
else:
while tmp > 0:
pHead2 = pHead2.next
tmp -= 1
while pHead1 and pHead2:
if pHead1 == pHead2:
return pHead1
pHead1 = pHead1.next
pHead2 = pHead2.next
数值的整数次方
参考:https://www.nowcoder.com/questionTerminal/1a834e5e3e1a4b7ba251417554e07c00?answerType=1&f=discussion
然后是两种方法:
# -*- coding:utf-8 -*-
class Solution:
def Power(self, base, exponent):
# write code here
if exponent == 0:
return 1.0
if exponent < 0:
base = 1 / base
exponent = -exponent
tmp = self.Power(base, exponent/2)
if exponent % 2 == 0:
res = tmp * tmp
else:
res = tmp * tmp * base
return res