leetcode刷题 166~
题目166
分数到小数
给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以字符串形式返回小数。
如果小数部分为循环小数,则将循环的部分括在括号内。
思路
长除法,考虑负数/循环小数/整数等多种情况
实现
import collections class Solution: def fractionToDecimal(self, numerator: int, denominator: int) -> str: l = '' if numerator*denominator <0: numerator = abs(numerator) denominator = abs(denominator) l = '-' visied = collections.OrderedDict() pos = numerator // denominator left = numerator % denominator flag = False begin = None if left == 0: return l+str(pos) # visied[numerator] = pos while left != 0: num = left *10 left = num % denominator reco = num // denominator if num in visied.keys(): flag = True begin = num break else: visied[num] = reco result = '' for i in visied.keys(): if begin == i: result += '(' result += str(visied[i]) if flag is True: result = result + ')' result = str(pos) + '.' + result return l+result
题目167
两数之和
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 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: Sum = numbers[left] + numbers[right] if Sum == target: return left+1,right+1 elif Sum > target: right -= 1 else: left +=1
题目166
Excel表列名称
给定一个正整数,返回它在 Excel 表中相对应的列名称。
例如,
1 -> A
2 -> B
3 -> C
...
26 -> Z
27 -> AA
28 -> AB
...
思路
用除留余数法将数字由 10 进制转换为 26 进制
实现
class Solution: def convertToTitle(self, n: int) -> str: result = '' while n != 0: n -= 1 tmp = chr(65 + n % 26) result = tmp + result n //= 26 return result
题目169
多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
思路
方法思路很多,详见https://leetcode-cn.com/problems/majority-element/solution/duo-shu-yuan-su-by-leetcode-solution/
摩尔投票法
实现
class Solution: def majorityElement(self, nums: List[int]) -> int: result = nums[0] count = 1 for i in range(1,len(nums)): if count == 0: result = nums[i] count = 1 else: if nums[i] == result: count += 1 else: count -= 1 return result
题目171
excel表列序号
给定一个Excel表格中的列名称,返回其相应的列序号。
例如,
A -> 1
B -> 2
C -> 3
...
Z -> 26
AA -> 27
AB -> 28
..
思路
二十六进制
实现
class Solution: def titleToNumber(self, s: str) -> int: result = 0 for i in s: result = result*26 temp = ord(i) - 64 result += temp return result
题目172
阶乘后的零
给定一个整数 n,返回 n! 结果尾数中零的数量。
思路
阶乘到5的倍数才会新增零,遇到25的倍数新增2个零,125三个零,以此类推
实现
class Solution: def trailingZeroes(self, n: int) -> int: result = 0 index = 5 while n >= index: result += (n // index) index *= 5 return result
题目173
二叉搜索树迭代器
实现一个二叉搜索树迭代器。你将使用二叉搜索树的根节点初始化迭代器。
调用 next()
将返回二叉搜索树中的下一个最小的数。
思路
中序遍历
实现
class BSTIterator: def __init__(self, root: TreeNode): self.stack = [] def helper(node): if node.left: helper(node.left) self.stack.append(node.val) if node.right: helper(node.right) if root: helper(root) def next(self) -> int: """ @return the next smallest number """ result =self.stack[0] self.stack.remove(self.stack[0]) return result def hasNext(self) -> bool: """ @return whether we have a next smallest number """ if self.stack: return True else: return False
题目187
重复的DNA
思路
1.暴力法,hash表
2.见leetcode解答,没有看懂 https://leetcode-cn.com/problems/repeated-dna-sequences/solution/zhong-fu-de-dnaxu-lie-by-leetcode/
实现
class Solution: def findRepeatedDnaSequences(self, s: str) -> List[str]: window = set() result = set() leng = 10 for i in range(len(s)-leng+1): temp = s[i:i+leng] if temp in window: result.add(temp) window.add(temp) return list(result)
题目189
旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
思路
首先将所有元素反转。然后反转前 k 个元素,再反转后面 n−k 个元素
原始数组 : 1 2 3 4 5 6 7
反转所有数字后 : 7 6 5 4 3 2 1
反转前 k 个数字后 : 5 6 7 4 3 2 1
反转后 n-k 个数字后 : 5 6 7 1 2 3 4 --> 结果
实现
class Solution: def rotate(self, nums: List[int], k: int) -> None: """ Do not return anything, modify nums in-place instead. """ k = k%len(nums) nums.reverse() nums[:k] = nums[:k][::-1] nums[k:] = nums[k:][::-1]
题目190
颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。
示例 1:
输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
思路
实现
class Solution: def reverseBits(self, n: int) -> int: result = 0 num = 0 while num != 32: result = result*2 +(n % 2) n = n//2 num += 1 return result
题目191
位1的个数
编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
思路
实现
class Solution: def hammingWeight(self, n: int) -> int: count = 0 mask = 1 num = 0 while num != 32: if n & mask !=0: count += 1 mask <<= 1 num += 1 return count
题目198
打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
思路
动态规划
实现
class Solution: def rob(self, nums: List[int]) -> int: if not nums: return 0 l = len(nums) if l ==1 : return nums[0] result = [0 for _ in range(l)] result[0] = nums[0] result[1] = nums[1] res = max(nums[0],nums[1]) temp = result[0] for i in range(2,l): result[i] = nums[i] + temp if result[i] > res: res = result[i] if result[i-1] > temp: temp = result[i -1] return res
题目199
二叉树的右视图
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
思路
广度优先遍历/深度优先遍历
实现
from collections import deque class Solution: def rightSideView(self, root: TreeNode) -> List[int]: if not root: return [] queue = deque() queue.append((root,0)) result = dict() while queue: node,depth = queue.popleft() result[depth] = node.val if node.left: queue.append((node.left,depth+1)) if node.right: queue.append((node.right,depth+1)) return list(result.values())
题目200
岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:
[
['1','1','1','1','0'],
['1','1','0','1','0'],
['1','1','0','0','0'],
['0','0','0','0','0']
]
输出: 1
思路
深度优先遍历
实现
class Solution: def numIslands(self, grid: List[List[str]]) -> int: row = len(grid) if row == 0: return 0 col = len(grid[0]) result = 0 for i in range(row): for j in range(col): if grid[i][j] == '1': result += 1 self.dfs(grid,i,j) return result def dfs(self, grid, i, j): grid[i][j] = '0' row, col = len(grid), len(grid[0]) for x, y in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= x < row and 0 <= y < col and grid[x][y] == "1": self.dfs(grid, x, y)
题目201
数字范围按位与
给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
思路
参考的官方答案:问题等效于问题给定两个整数,我们要找到它们对应的二进制字符串的公共前缀。
1.位移
将两个数字不断向右移动,直到数字相等,即数字被缩减为它们的公共前缀。然后,通过将公共前缀向左移动,将零添加到公共前缀的右边以获得最终结果。
2.Brian Kernighan 算法
Brian Kernighan 算法的关键在于我们每次对 number和 number-1之间进行按位与运算后,number 中最右边的 1会被抹去变成 0。可以对数字 nn迭代地应用上述技巧,清除最右边的 1,直到它小于或等于 m,此时非公共前缀部分的 1均被消去。
实现
1. class Solution: def rangeBitwiseAnd(self, m: int, n: int) -> int: shift = 0 # 找到公共前缀 while m < n: m = m >> 1 n = n >> 1 shift += 1 return m << shift 2. class Solution: def rangeBitwiseAnd(self, m: int, n: int) -> int: while m < n: # 抹去最右边的 1 n = n & (n - 1) return n
题目202
快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
思路
实现
class Solution: def isHappy(self, n: int) -> bool: def get_next(n: int) -> int: temp = 0 while n > 0: n, digit = divmod(n, 10) temp += digit ** 2 return temp visited = set() while n != 1 and n not in visited: visited.add(n) n = get_next(n) return n==1
题目203
移除链表元素
删除链表中等于给定值 val 的所有节点。
思路实现
class Solution: def removeElements(self, head: ListNode, val: int) -> ListNode: result = ListNode(None) result.next = head before = result while head: if head.val != val: before = head else: before.next = head.next head = head.next return result.next
题目204
计数质数
统计所有小于非负整数 n
的质数的数量。
思路
厄拉多塞筛法:
要得到自然数n以内的全部质数,必须把不大于根号n的所有质数的倍数剔除,剩下的就是质数。
实现
class Solution: def countPrimes(self, n: int) -> int: if n < 2: return 0 primes = [1 for _ in range(n)] primes[0] = primes[1] = 0 for i in range(2,int(n**0.5)+1): j = i while i * j < n: primes[i*j] = 0 j += 1 return sum(primes)
题目205
同构字符串
给定两个字符串 s 和 t,判断它们是否是同构的。
如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。
所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
思路
字典
实现
class Solution: def isIsomorphic(self, s: str, t: str) -> bool: a = dict() b = dict() for i in range(len(s)): a[s[i]] = t[i] b[t[i]] = s[i] for i in range(len(s)): if a[s[i]] != t[i] or b[t[i]] != s[i]: return False return True
题目206
反转链表
反转一个单链表。
思路实现
class Solution: def reverseList(self, head: ListNode) -> ListNode: result = None while head: node = head.next head.next = result result = head head = node return result
题目207
课程表
你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
思路
思路很简单,深度优先遍历即可,当遍历到重复的点时,说明出现环,则失败
实现
class Solution: def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: on_stack = [False for _ in range(numCourses)] visited = [False for _ in range(numCourses)] edges = collections.defaultdict(list) flag = True for info in prerequisites: edges[info[0]].append(info[1]) def dfs(cur, on_stack): nonlocal flag on_stack[cur] = True visited[i] = True for pre_cour in edges[cur]: if on_stack[pre_cour] is False: if not visited[pre_cour]: dfs(pre_cour,on_stack) else: flag = False return on_stack[cur] = False for i in range(numCourses): if not visited[i] and flag: dfs(i,on_stack) return flag
效率偏低,可以优化
题目208
实现Trie
实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。
示例:
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // 返回 true
trie.search("app"); // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");
trie.search("app"); // 返回 true
思路
Trie 树是一个有根的树,其结点具有以下字段:。
·最多 R个指向子结点的链接,其中每个链接对应字母表数据集中的一个字母。本文中假定 R 为 26,小写拉丁字母的数量。
·布尔字段,以指定节点是对应键的结尾还是只是键前缀。
实现
class Node: def __init__(self, val=None ,end = False): self.val = val self.is_end = end self.next = {} class Trie: def __init__(self): """ Initialize your data structure here. """ self.root = Node() def insert(self, word: str) -> None: """ Inserts a word into the trie. """ node = self.root for i in word: if i not in node.next: node.next[i] = Node(i) node = node.next[i] node.is_end = True def search(self, word: str) -> bool: """ Returns if the word is in the trie. """ node = self.root for i in word: if i not in node.next: return False node = node.next[i] if node.is_end is False: return False return True def startsWith(self, prefix: str) -> bool: """ Returns if there is any word in the trie that starts with the given prefix. """ node = self.root for i in prefix: if i not in node.next: return False node = node.next[i] return True