155,160,167,168,169,171,172
155:最小栈
题目描述:
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
思路:
1:用两个栈,一个栈去保存正常的入栈出栈的值,另一个栈去存最小值,也就是用栈顶保存当前所有元素的最小值。
存最小值的栈的具体操作流程如下:
将第一个元素入栈。新加入的元素如果大于栈顶元素,那么新加入的元素就不处理。新加入的元素如果小于等于栈顶元素,那么就将新元素入栈。出栈元素不等于栈顶元素,不操作。出栈元素等于栈顶元素,那么就将栈顶元素出栈。
2:一个栈(主要解决当前出栈为最小值必须找到前一个最小值):
(1)当有更小的值来的时候,我们只需要把之前的最小值入栈,当前更小的值再入栈即可。当这个最小值要出栈的时候,出栈两次,第二次的值便是之前的最小值了。
(2)每次存入的是 原来值 - 当前最小值
当原来值大于等于当前最小值的时候,我们存入的肯定就是非负数,所以出栈的时候就是 栈中的值 + 当前最小值
当原来值小于当前最小值的时候,我们存入的肯定就是负值,此时的值我们不入栈,用 min 保存起来,同时将差值入栈。
当后续如果出栈元素是负数的时候,那么要出栈的元素其实就是 min
此外之前的 min 值,我们可以通过栈顶的值和当前 min 值进行还原,就是用 min 减去栈顶元素即可。
代码:
160:相交链表
题目描述:
编写一个程序,找到两个单链表相交的起始节点。
思路:
使两个链表到达相等位置时走过的是相同的距离,链表1的长度是x1+y,链表2的长度是x2+y,我们同时遍历链表1和链表2,到达末尾时,再指向另一个链表。
则当两链表走到相等的位置时:x1+y+x2 = x2+y+x1
代码:
p = headA
q = headB
while p!=q:
p = p.next if p else headB
q = q.next if q else headA
return p
167:两数之和Ⅱ-输入有序数组
题目描述:
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
思路:
用两个指针,初始分别位于第一个元素和最后一个元素位置,比较这两个元素之和与目标值的大小。如果和等于目标值,我们发现了这个唯一解。如果比目标值小,我们将较小元素指针增加一。如果比目标值大,我们将较大指针减小一。
代码:
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
left = 0
right = len(numbers)-1
while left < right:
if numbers[left] + numbers[right] == target:
return [left+1, right+1]
elif numbers[left] + numbers[right] < target:
left = left + 1
else:
right = right - 1
168:Excel表列名称
题目描述:
给定一个正整数,返回它在 Excel 表中相对应的列名称。
思路:
将n对26取余后,余数125对应’A’‘Y’,而0对应的是’Z’。虽然26对26取余为0,但是表达式中存在26(‘Z’),所以每次得到余数为0时,不仅要加入’Z’,还要在原数n中减去26(1~26都可以,毕竟后面还要进行取余运算)。
代码:
a=''
while n:
n-=1
a=chr(n%26+65)+a
n=n/26
return a
169:求众数
题目描述:
给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
思路:
此题最为关键的就是注意这里的众数定义是一个数的出现次数大于一半,等于都不行,必须是大于一半,所以可以这样想如果众数为1,而其他数令为-1,则所有数之和一定大于0.因此,我们可以采取一种类似于同归于尽的方式(Boyer-Moore 投票算法),即,我们从头开始令target为目标数字,每找到一个数,我们就令其个数为1,然后遍历之和的数字,如果与之相同则数目加一,如果不同则数目减一,此时应该注意,减一之后应该判断这个数字的个数是否为0如果为0就说明该数目已经抵消一个数字。然后重新选择一个目标数字target以此循环,到最后这个target一定为众数。因为数字之间相互抵消,众数是大于一半的,一个众数抵消一个其他数字也能把其他数字抵消完,最后剩下的一定是众数。同时应该注意,此题已经告诉众数已经存在,如果没有这个条件还需要在最后再遍历一遍判断target的数目是否过了一半。
代码:
class Solution:
def majorityElement(self, nums: List[int]) -> int:
count = 1
# 首先选取第一个作为基准
base = nums[0]
for i in range(1, len(nums)):
# 遇到相同的数则计数加1
if base == nums[i]:
count += 1
else:
# 遇到不同的计数减1
count -= 1
# 如果计数为0,则取下一个为基准
if count == 0:
base = nums[i + 1]
# 最后一定基准的数的count大于0
return base
171:Excel表列序号
题目描述:
给定一个Excel表格中的列名称,返回其相应的列序号。
思路:
字符串遍历,进制转换
初始化结果ans = 0,遍历时将每个字母与A做减法,因为A表示1,所以减法后需要每个数加1,计算其代表的数值字母 - ‘A’ + 1
因为有26个字母,所以相当于26进制,每26个数则向前进一位
代码:
class Solution(object):
def titleToNumber(self, s):
#26进制转10进制
ans = 0
for x in s:
ans *= 26
ans += ord(x)-ord('A')+1
return ans
172:阶乘后的零
题目描述:
给定一个整数 n,返回 n! 结果尾数中零的数量。
思路:
N!有多少个后缀0,即N!有多少个质因数5
N!有多少个质因数5,即N可以划分成多少组5个数字一组,加上划分成多少组25个数字一组,加上划分多少组成125个数字一组。。。
比如5 的阶乘是120 后面有一个0. 为了统计处这样的0 有多少个。我们只需要知道所有可能的数字 里面相乘 可以得到10 的个数。
比如5! = 54321 其中 52得到10;这就是最后一个0 的来源
在思考一下,要得到整数10 只能由 25 得到,我们可以把问题转换成为 寻找<n 的所有数字中 的分解 因子中的2 和5 的个数。一个2和一个5 就能构成10 。
比如10! =(25)9(24)7(23)(51)(22)3(21)
其中有 6个2 2个5 只能构成两个10 所以 10 的结果应该是2
并且我们发现统计2的个数没有意义的。2 的个数必然比5 多。因此我们只需要统计5 的个数就行了。
但是要知道有的数能整除5,但他的结果也为5。例如25。
每5个一组,N!里质因数5的个数要比前一组多一个
代码:
if n<5:
return 0
else:
return n/5+self.trailingZeroes(n/5)