刷题四道,但是还是不牢固,需要再写。
参考与感谢:https://codingcat.cn/article/30
丑数
字符串的排列
两个链表的第一个公共节点
二叉树的深度
丑数
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路:
除了1之外,丑数都是由某个丑数2或者3或者*5得到的。方法1,从1开始去验证每个数是否是丑数,结束条件为已记录的丑数个数为目标值
方法2: 用生成的方法,因为,丑数都是由某个丑数2或者3或者*5得到的生成的,所以可以保存之前已求出的丑数,用来生成后续的丑数。关键是如何去生成与排序后续的丑数
**解决方式:用一个数组,按大小存放当前已经找到的丑数。假设当前数组中最大的丑数是M,要找一个新的丑数,则是根据列表中当前的数x去乘以2,3,5,生成出来的,去保存生成的结果。假设数组中已经有若干个丑数排好序后存放在数组中,并且把己有最大的丑数记做M。我们首先考虑把已有的每个丑数乘以 2。在乘以 2 的时钝能得到若干个小于或等于 M 的结果。由于是按照顺序生成的,小于或者等于 M 肯定己经在数组中了,我们不需再次考虑:还会得到若干个大于 M 的结果,但我们只需要第一个大于 M 的结果,因为我们希望丑数是按从小到大的顺序生成的,其他更大的结果以后再说。我们把得到的第一个乘以 2 后大于 M 的结果记为 M2,同样,我们把已有的每一个丑数乘以 3 和 5,能得到第一个大于 M 的结果 M3 和 M,那么下一个丑数应该是 M2、M3 和 M5 这 3 个数的最小者。
前面分析的时候,提到把已有的每个丑数分别都乘以 2、3 和 5。事实上这不是必须的,因为已有的丑数是按顺序存放在数组中的。对乘以 2 而言, 肯定存在某一个丑数 T2,排在它之前的每一个丑数乘以 2 得到的结果都会小于已有最大的丑数,在它之后的每一个丑数乘以 2 得到的结果都会太大。我们只需记下这个丑数的位置, 同时每次生成新的丑数的时候,去更新这个 T2。对乘以 3 和 5 而言, 也存在着同样的 T3 和 T5。**
# -*- coding:utf-8 -*-
class Solution:
def GetUglyNumber_Solution(self, index):
# write code here
if index <7: #如果不加判断<7的情况,牛客测试不能完全通过,不知为啥。感觉只用判断是佛为0即可
return index
numbers= [1,]
p2 = 0
p3 = 0
p5 = 0
MUglyIndex=1
while len(numbers) < index:
min_M=min(numbers[p2]*2,numbers[p3]*3,numbers[p5]*5)
numbers.append(min_M)
#numbers[nextUglyIndex]=min_M
while(numbers[p2]*2<=numbers[MUglyIndex]): #此处记录位置
p2 +=1
while(numbers[p3]*3<=numbers[MUglyIndex]):
p3 +=1
while(numbers[p5]*5<=numbers[MUglyIndex]):
p5 +=1
MUglyIndex+=1
print(len(numbers))
return numbers[-1]
字符串的排列
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
思路:
这相当于一个排列组合的问题。以abc为例,思考一下如果人工做这个题的思路。首先是固定首位为a,那么剩下bc,第二位若排b,第三位则排c,否则二c三b,所以可以排出abc,acb。然后首位为b,剩下ac,可以排出bac,bca。然后首位为c,剩下ab,可以排出cab,cba。
整体思路应该是,先固定首位,然后余下的部分做排列;余下部分固定首位,再余下做排列……是一种递归的思路。
思路还可以,实现的时候要想清楚细节。
在具体实现中,固定首位取余下,代码方面可以这样做:字符串的首位依次与后边交换,比如说 abc,首位a先与它自己a换,即abc,然后递归bc;首位a再与b换,即bac,然后递归ac(递归后,记得再换回去);首位a再与c换,得到cba,然后递归ba……
因为题目要求字典序打印,而且输入中会有重复字符,所以对最终得到的list要做去重,然后字典序排序。
# -*- coding:utf-8 -*-
class Solution:
def Permutation(self, ss):
if len(ss) <=0:
return []
res = list()
self.perm(ss,res,'')
uniq = list(set(res))
return sorted(uniq)
def perm(self,ss,res,path):
if ss=='':
res.append(path)
else:
for i in range(len(ss)):
self.perm(ss[:i]+ss[i+1:],res,path+ss[i])
两个链表的第一个公共节点
输入两个链表,找出它们的第一个公共结点。
思路:利用链表共节点的特性:
#先两个各遍历一遍,得到两个链表的长度。计算长度差,让长的先走一段,
#走到两个链表余下长度相同时,两个链表同时继续走,并比较元素,就能找到第一个相同元素。
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#链表如果共节点,则会从第一个公共结点开始,之后的结点都是公共结点。先两个各遍历一遍,得到两个链表的长度。计算长度差,让长的先走一段,
#走到两个链表余下长度相同时,两个链表同时继续走,并比较元素,就能找到第一个相同元素。
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
if not pHead1 or not pHead2:
return None
len1 = 0
len2 = 0
ptr1 = pHead1
ptr2 = pHead2
while ptr1:
len1 += 1
ptr1 = ptr1.next
while ptr2:
len2 += 1
ptr2 = ptr2.next
ptr1 = pHead1
ptr2 = pHead2
while len1 > len2:
ptr1 = ptr1.next
len1 -= 1
while len2 > len1:
ptr2 = ptr2.next
len2 -= 1
while len1 > 0:
if id(ptr1) == id(ptr2):
return ptr1
else:
ptr1 = ptr1.next
ptr2 = ptr2.next
len1 -= 1
#这个代码简洁多了
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def FindFirstCommonNode(self, head1, head2):
# write code here
list1 = []
list2 = []
node1 = head1
node2 = head2
while node1:
list1.append(node1.val)
node1 = node1.next
while node2:
if node2.val in list1:
return node2
else:
node2 = node2.next
二叉树的深度
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
思路: 递归记录。树的深度为当前深度加左右子树深度的较大值。具体分析:树只有1个节点,其深度为1;如果根节点只有左子树,则深度为左子树的深度+1;如果只有右子树,则深度为右子树深度+1;如果左右都有,则深度为左右的深度的较大值+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):
# write code here
if not pRoot:
return 0
left = self.TreeDepth(pRoot.left)
right=self.TreeDepth(pRoot.right)
return max(left,right)+1