目录
1. 两数之和
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
class Solution:
def twoSum(self, nums, target):
dic = {}
for i, num in enumerate(nums):
if num in dic:
return [dic[num], i]
else:
dic[target - num] = i
# enumerate()函数将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标。一般用在for循环当中。
2. 两数相加
给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
class Solution:
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
ans = ListNode(0) #新建一个节点,初始值为0
temp = ans
tempsum = 0
while True:
if (l1 != None):
tempsum = l1.val + tempsum #l1链表节点值添加到总和里
l1 = l1.next #指针指向下一个节点
if (l2 != None):
tempsum = tempsum + l2.val #l2链表节点值添加到总和里
l2 = l2.next #指针指向下一个节点
temp.val = tempsum % 10 #取余数(满十进位),赋值当前节点值
print(tempsum)
tempsum = int(tempsum / 10) #获取进位数赋值给总和(比如tempsum为10则进1位,否则进位为0),下一次节点相加,从新的总和开始。
if l1 == None and l2 == None and tempsum == 0: #直到没有进位了,同时节点位空了,跳出循环。(这里加上tempsum==0条件是因为,最后两个节
break #点和值可能大于10)
temp.next = ListNode(0) #新建下一个节点,存放和
temp = temp.next #指针指向下一个节点
return ans
ListNode定义:
struct ListNode {
int val; //定义val变量值,存储节点值
struct ListNode *next; //定义next指针,指向下一个节点,维持节点连接
}
- 在节点ListNode定义中,定义为节点为结构变量。
- 节点存储了两个变量:value 和 next。value 是这个节点的值,next 是指向下一节点的指针,当 next 为空指针时,这个节点是链表的最后一个节点。
- 注意注意val只代表当前指针的值,比如p->val表示p指针的指向的值;而p->next表示链表下一个节点,也是一个指针。
- 构造函数包含两个参数 _value 和 _next ,分别用来给节点赋值和指定下一节点
3. 无重复字符的最长子串
给定一个字符串,找出不含有重复字符的最长子串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 无重复字符的最长子串是"abc",其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 无重复字符的最长子串是 "b",其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 无重复字符的最长子串是 "wke",其长度为 3。请注意,答案必须是一个子串,"pwke" 是一个子序列 而不是子串。
class Solution:
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
max_len = 0 # 存储历史循环中最长的子串长度
if s is None or len(s) == 0: # 判断传入的字符串是否为空
return max_len
str_dict = {} # 定义一个字典,存储不重复的字符和字符所在的下标
one_max = 0 # 存储每次循环中最长的子串长度
start = 0 # 记录最近重复字符所在的位置+1
for i in range(len(s)):
if s[i] in str_dict and str_dict[s[i]] >= start: # 判断当前字符是否在字典中和当前字符的下标是否大于等于最近重复字符的所在位置
start = str_dict[s[i]] + 1 # 记录当前字符的值+1
one_max = i - start + 1 # 在此次循环中,最大的不重复子串的长度
str_dict[s[i]] = i # 把当前位置覆盖字典中的位置
max_len = max(max_len, one_max) # 比较此次循环的最大不重复子串长度和历史循环最大不重复子串长度
return max_len
子串与子序列:
4. 两个排序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
你可以假设 nums1 和 nums2 不同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
中位数是 (2 + 3)/2 = 2.5
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
nums = sorted(nums1 + nums2)
mid_num = 0
if len(nums) % 2 == 0:
mid_num = float((nums[len(nums) // 2 - 1] + nums[len(nums) // 2]) / 2)
else:
mid_num = float(nums[len(nums) // 2])
return mid_num
在描述算法复杂度时,经常用到o(1), o(n), o(logn), o(nlogn)来表示对应算法的时间复杂度, 这里进行归纳一下它们代表的含义: 这是算法的时空复杂度的表示。不仅仅用于表示时间复杂度,也用于表示空间复杂度。
O后面的括号中有一个函数,指明某个算法的耗时/耗空间与数据增长量之间的关系。其中的n代表输入数据的量。
(1)时间复杂度为O(n):数据量增大几倍,耗时也增大几倍。比如常见的遍历算法。
(2)时间复杂度O(n^2):数据量增大n倍时,耗时增大n的平方倍,这是比线性更高的时间复杂度。比如冒泡排序,就是典型的O(n^2)的算法,对n个数排序,需要扫描n×n次。
(3)O(logn),当数据增大n倍时,耗时增大logn倍(这里的log是以2为底的,比如,当数据增大256倍时,耗时只增大8倍,是比线性还要低的时间复杂度)。二分查找就是O(logn)的算法,每找一次排除一半的可能,256个数据中查找只要找8次就可以找到目标。
(4)O(nlogn)同理,就是n乘以logn,当数据增大256倍时,耗时增大256*8=2048倍。这个复杂度高于线性低于平方。归并排序就是O(nlogn)的时间复杂度。
(5)O(1)就是最低的时空复杂度了,也就是耗时/耗空间与输入数据大小无关,无论输入数据增大多少倍,耗时/耗空间都不变。 哈希算法就是典型的O(1)时间复杂度,无论数据规模多大,都可以在一次计算后找到目标(不考虑冲突的话)。
5. 最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
s = '#' + '#'.join(s)+'#'
RL = [0]*len(s)
MaxRight = 0
pos = 0
MaxLen = 0
for i in range(len(s)):
if i <MaxRight:
RL[i] = min(RL[2*pos-i], MaxRight-i)
else:
RL[i] = 1
while i-RL[i]>=0 and i+RL[i]<len(s) and s[i-RL[i]] == s[i+RL[i]]: #尝试扩展,注意处理边界
RL[i] += 1
if RL[i] +i-1 >MaxRight: #更新MaxRight,pos
MaxRight = RL[i]+i-1
pos = i
MaxLen = max(MaxLen,RL[i]) #更新最长回文串的长度
if MaxLen == RL[i]:
MaxList = s[i-RL[i]+1:i+RL[i]]
return MaxList.replace("#",'')
6.Z字形变换
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "LEETCODEISHIRING"
行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"
。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"
示例 2:
输入: s = "LEETCODEISHIRING", numRows = 4 输出: "LDREOEIIECIHNTSG" 解释: L D R E O E I I E C I H N T S G
class Solution:
def convert(self, s, numRows):
"""
:type s: str
:type numRows: int
:rtype: str
"""
if numRows < 2:
return s
rows = [''] * min(numRows,len(s))
godown = False
currow = 0
for c in s:
rows[currow] += c
if currow == 0 or currow == numRows -1:
godown = not godown
if godown:
currow += 1
else:
currow -= 1
return ''.join(rows)
7.正数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123 输出: 321
示例 2:
输入: -123 输出: -321
示例 3:
输入: 120 输出: 21
注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
class Solution:
def reverse(self, x):
"""
:type x: int
:rtype: int
"""
# 个位数不用反转
if -10 < x < 10:
return x
# 负数转为正数
if x < 0:
str_x = str(-x)[::-1]
y = int(str_x)
y = -y
else:
str_x = str(x)[::-1]
y = int(str_x)
# 如果-2147483648 < x < 2147483647则返回x,否则返回0
return y if -2147483648 < y < 2147483647 else 0
8.字符串转换整数 (atoi)
请你来实现一个 atoi
函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,qing返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
输入: "42" 输出: 42
示例 2:
输入: " -42" 输出: -42 解释: 第一个非空白字符为 '-', 它是一个负号。 我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: "4193 with words" 输出: 4193 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4:
输入: "words and 987" 输出: 0 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 因此无法执行有效的转换。
示例 5:
输入: "-91283472332" 输出: -2147483648 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (−231) 。
class Solution:
def myAtoi(self, str):
"""
:type str: str
:rtype: int
"""
str0 = str.lstrip() # 删除字符串前面的空格
if len(str0) == 0:
return 0
pos = 1 # 用pos记录整数的正负
if str0[0] == '-':
pos = -1
str0 = str0[1:] # 若首字符为正负号则用pos记录并删除首字符
elif str0[0] == '+':
pos = 1
str0 = str0[1:]
if len(str0) == 0: # 若删除首字符后字符串为空则返回为0
return 0
if str0[0].isdigit(): #若首字符不为数字则返回为0
pass
else:
return 0
i = 0
while(i < len(str0)):
if str0[i].isdigit():
i += 1
else:
break
result = pos * int(str0[0:i])
max_int = pow(2, 31) - 1
min_int = -pow(2, 31)
if result > max_int:
return max_int
if result < min_int:
return min_int
return result
9.回文数
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121 输出: true
示例 2:
输入: -121 输出: false 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入: 10 输出: false 解释: 从右向左读, 为 01 。因此它不是一个回文数。
class Solution:
# 整数转字符串,通过下标对比确定该整数是否为回文数
def isPalindrome(self, x):
"""
:type x: int
:rtype: bool
"""
str_x = str(x)
for i in range(0,int(len(str_x)/2)):
if str_x[i] != str_x[-i-1]:
return False
return True
# 字符串切片操作,str[index:index:step],中括号里面分别为:字符起点、终点和步长
def isPalindrome(self, x):
str_x = str(x)
return str_x == str_x[::-1]
# 数学计算的方法,对比反转整数的值
def isPalindrome(self, x):
if x<0:
return False
temp_x = x;
palindromeNum = 0
while temp_x != 0:
palindromeNum = palindromeNum*10 + temp_x%10
temp_x /= 10
return palindromeNum == x
# 整数转字符串,反转字符串,对比反转后字符串与原字符串是否相等
def isPalindrome(self, x):
str_x = str(x)
str_y = ""
for i in str_x:
str_y = i + str_y
return str_y == str_x