学习目标:
- 刷完面试经典150题
- 链接: 面试经典150题
学习内容:
-
- 快乐数
-
- 只出现一次的数字
-
- x 的平方根
-
- 位1的个数
-
- 颠倒二进制位
-
- 完全二叉树的节点个数
-
- 路径总和
-
- 两数之和
-
- 存在重复元素 II
学习时间:
4.11
今儿就来个大扫荡,把我剩下的简单题全部干掉好了
知识点
学习内容:
202. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。 如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
说是快乐数,可是仔细做做题,好像也没有那么快乐,哼!
这道题的描述的运算算法不难,但是重点在于他的停止条件怎么判断。
我原来写的程序要么内存堆栈炸掉,要么写错了。
看了题解,有一个快慢指针的思想。很容易理解。
-
考虑这样一种情况,用sum表示各个位数的和。如果sum始终到不了1,说明一定存在无限循环的情况。如果无限循环,那么在这期间sum一定一直在重复某些值得循环。
-
所以假设sum的所有取值是一个链表序列
-
第一种情况:如果sum是无限循环的情况,那么这个链表一定有环。如图所示
-
第二种情况:如果sum不是无限循环的情况,那么这个链表一定没有环,而且最后一个节点一定是1(因为1的平方还是1,后面的序列会一直是1)
-
设置快慢指针,慢指针等于链表序列的第一个元素,快指针等于第二个元素。
-
停止条件是快慢指针相等,如果相等的值等于1,那么是第二种情况。如果相等的值不等于1,则是第一种情况
代码:
class Solution(object):
def isHappy(self, n):
"""
:type n: int
:rtype: bool
"""
def get_next(n):
sum = 0
for i in str(n):
sum += int(i) ** 2
return sum
slow=n #慢指针等于的序列的第一个值
fast=get_next(n) #快指针等于序列的第二个值
while slow!=fast:
slow=get_next(slow) #慢指针每次移动一个元素
fast=get_next(get_next(fast)) #快指针每次移动两个元素
return slow==1
if __name__ == "__main__":
s = Solution()
n=19
print(s.isHappy(n))
136. 只出现一次的数字
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
输入:nums = [2,2,1] 输出:1
示例 2 :输入:nums = [4,1,2,1,2] 输出:4
示例 3 :输入:nums = [1] 输出:1
代码:
class Solution(object):
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
dict1={}
for i in nums:
if i in dict1:
dict1[i]+=1
continue
dict1[i]=1
for i in dict1.keys():
if dict1[i]==1:
return i
if __name__ == "__main__":
s = Solution()
nums = [4,1,2,1,2]
print(s.singleNumber(nums))
69. x 的平方根
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
示例 1:
输入:x = 4 输出:2
示例 2:输入:x = 8 输出:2
解释:8 的算术平方根是 2.82842…, 由于返回类型是整数,小数部分将被舍去。
import math
class Solution(object):
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
return int(math.sqrt(x))
if __name__ == "__main__":
s = Solution()
x = 8
print(s.mySqrt(x))
191. 位1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中 设置位 的个数(也被称为汉明重量)。
示例 1:
输入:n = 11 输出:3
解释:输入的二进制串 1011 中,共有 3 个设置位。
示例 2:输入:n = 128 输出:1
解释:输入的二进制串 10000000 中,共有 1 个设置位。
示例 3:输入:n = 2147483645 输出:30
解释:输入的二进制串 11111111111111111111111111111101
中,共有 30 个设置位。
直接把数字想象成二进制的形式,不断地进行模2运算,后右移,直至为0
代码:
class Solution(object):
def hammingWeight(self, n):
"""
:type n: int
:rtype: int
"""
i=1
sum=0
while n!=0:
if n%2==1:
sum+=1
n=n>>1
return sum
if __name__ == "__main__":
s = Solution()
x = 11
print(s.hammingWeight(x))
190. 颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。
提示:
请注意,在某些语言(如> Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在 示例 2 中,输入表示有符号整数 -3,输出表示有符号整数
-1073741825。示例 1:
输入:n = 00000010100101000001111010011100 输出:964176192
(00111001011110000010100101000000)
解释:输入的二进制串
00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
示例 2:输入:n = 11111111111111111111111111111101 输出:3221225471
(10111111111111111111111111111111)
解释:输入的二进制串
11111111111111111111111111111101 表示无符号整数 4294967293,
因此返回 3221225471 其二进制表示形式为 10111111111111111111111111111111 。提示:
输入是一个长度为 32 的二进制字符串
代码:
class Solution:
# @param n, an integer
# @return an integer
def reverseBits(self, n):
a=str(bin(n))[2:] ##因为转二进制的时候会自动在前面加上0b,[2:]的作用是去掉0b
a=a.zfill(32) #把a用0自动补全到32位
a=a[::-1] #利用切片反转a
a=int('0b'+a,2) #二进制转10进制
return a
if __name__ == "__main__":
s = Solution()
n = 0b00000010100101000001111010011100
print(s.reverseBits(n))
222. 完全二叉树的节点个数
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树
的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第
h 层,则该层包含 1~ 2h 个节点。示例 1:
输入:root = [1,2,3,4,5,6] 输出:6
示例 2:输入:root = [] 输出:0
示例 3:输入:root = [1] 输出:1
如果不考虑时间复杂度这道题还是很简单的。。。
代码:
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution(object):
def __init__(self,val=0):
self.val=val
def countNodes(self, root):
"""
:type root: TreeNode
:rtype: int
"""
def visit(root):
if root.left:
visit(root.left)
self.val += 1
if root.right:
visit(root.right)
if root==None:
return 0
if root.left:
visit(root.left)
self.val+=1
if root.right:
visit(root.right)
return self.val
if __name__ == "__main__":
s = Solution()
root=TreeNode(1)
root.left=TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
root.right.left = TreeNode(6)
root.right.right = TreeNode(7)
print(s.countNodes(root))
112. 路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点
的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。叶子节点 是指没有子节点的节点。
示例 1:
https://assets.leetcode.com/uploads/2021/01/18/pathsum1.jpg
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。
示例 2:
输入:root = [1,2,3], targetSum = 5 输出:false
解释:树中存在两条根节点到叶子节点的路径: (1 -->
2): 和为 3 (1 --> 3): 和为 4 不存在 sum = 5 的根节点到叶子节点的路径。
示例 3:输入:root = [], targetSum = 0 输出:false 解释:由于树是空的,所以不存在根节点到叶子节点的路径。
代码:(记得改成python3)
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def hasPathSum(self, root, targetSum):
"""
:type root: TreeNode
:type targetSum: int
:rtype: bool
"""
if root==None:
return False
sum=root.val
max1=targetSum
flag=False
def visit(root,sum):
nonlocal flag
if root.left:
visit(root.left,sum+root.left.val)
if root.right:
visit(root.right,sum+root.right.val)
return
if not root.right and not root.left and sum==max1:
flag=True
visit(root,sum)
if flag:
return True
else:
return False
if __name__ == "__main__":
s = Solution()
root=TreeNode(1)
root.left=TreeNode(2)
# root.right = TreeNode(3)
# root.left.left = TreeNode(4)
# root.left.right = TreeNode(5)
# root.right.left = TreeNode(6)
# root.right.right = TreeNode(7)
print(s.hasPathSum(root,1))
1. 两数之和
简单题,不解释
代码:
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for i in range(len(nums)):
for j in range(i+1,len(nums)):
if nums[i]+nums[j]==target:
return (i,j)
return False
219. 存在重复元素 II
给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j]
且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false 。示例 1:
输入:nums = [1,2,3,1], k = 3 输出:true
示例 2:输入:nums = [1,0,1,1], k = 1 输出:true
示例 3:输入:nums = [1,2,3,1,2,3], k = 2 输出:false
暴力了一把,超时了,,,
改一改~
代码:
class Solution(object):
def containsNearbyDuplicate(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: bool
"""
n=len(nums)
if k>=n:
temp=set(nums)
if len(temp)<n:
return True
else:
return False
set1=set(nums[:k+1])
if len(set1)<k+1:
return True
for i in range(k+1,n):
set1.remove(nums[i-k-1])
set1.add((nums[i]))
if len(set1)!=k+1:
return True
return False
if __name__ == "__main__":
s = Solution()
nums=[1,2,3,1]
k = 3
print(s.containsNearbyDuplicate(nums,k))
最后成果
- 202. 快乐数
- 136. 只出现一次的数字
- 69. x 的平方根
- 191. 位1的个数
- 190. 颠倒二进制位
- 222. 完全二叉树的节点个数
- 112. 路径总和
- 1. 两数之和
- 219. 存在重复元素 II
结论
把简单题都做完了,一会就是中等起步了~~