Day1
First code
题目
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 :
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
解法
自己的解法
class Solution(object):
def twoSum(self, nums, target):
l=[]
flag=1
for x in range (0,len(nums)) :
for i in range (0,len(nums)) :
if i!=x :
if nums[i] + nums[x]==target :
l.append(nums[i])
l.append(nums[x])
flag=0
break
if flag==0 :
break
return l
标准答案
方法一
思路是找到num2=target-num1,判断是否也在list中。
使用以下两个方法
- num2 in nums,返回True,表示找到了。
- nums.index(num2),返回num2对应的索引。
def twoSum(nums, target):
lens = len(nums)
j=-1
for i in range(lens):
if (target - nums[i]) in nums: #找到可能的num2
if (nums.count(target - nums[i]) == 1)&(target - nums[i] == nums[i]):
#nums2出现了一次 & num1=num2
#如果num2=num1,且nums中只出现了一次,说明找到的是num1本身。
continue #跳过
else:
j = nums.index(target - nums[i],i+1)
#index(x,i+1)是从num1后的序列后找num2
#避免重复的方法
break
if j>0:
return [i,j]
else:
return []
方法二
优化方法一的解法,num2每次从num1之前找。
def twoSum(nums, target):
lens = len(nums)
j=-1
for i in range(1,lens):
temp = nums[:i]
if (target - nums[i]) in temp:
j = temp.index(target - nums[i])
break
if j>=0:
return [j,i]
方法三
用字典模拟哈希求解
def twoSum(nums, target):
hashmap={}
for ind,num in enumerate(nums):
hashmap[num] = ind
for i,num in enumerate(nums):
j = hashmap.get(target - num)
if j is not None and i!=j:
return [i,j]
方法四
类似方法二,优化方法三。
def twoSum(nums, target):
hashmap={}
for i,num in enumerate(nums):
if hashmap.get(target - num) is not None:
return [i,hashmap.get(target - num)]
hashmap[num] = i #这句不能放在if语句之前,解决list中有重复值或target-num=num的情况
Second Code
题目
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
示例 :
输入:x = 123
输出:321
解法
自己的解法
class Solution(object):
def reverse(self, x):
l = []
flag = True
if x < 0:
x = -x
flag = False
s = str(x)
ll = len(s)
n = 0
ex = 1
for i in range(0, ll - 1):
ex *= 10
for i in range(0, ll):
n += int(x % 10) * ex
x /= 10
ex /= 10
if flag:
return int(n)
else:
return -int(n)
ps : 注意判断负数以及判断反转后的情况
标准答案
class Solution :
def reverse(self,x) :
INT_MAX,INT_MIN=2**31-1,-2**31
rev=0
while x!=0 :
temp=int(x%10)
if (rev>INT_MAX//10) or (rev==INT_MAX//10 and temp>7) :
return 0
if (rev<INT_MIN//10) or (rev<INT_MIN//10 and temp<-8 ) :
return 0
rev=rev*10+temp
x//=10
return rev
- 语法学习 :
- python中 ** 表示乘方。
- //表示整数除法(注意这里一定要用// ,否则都是float)。
- 反转的思路 :
- 退出循环的条件是 x!=0。
- 如果等于0,表示x所有位数已遍历过。
- 由于有负数的条件,所以是不等于,不然的话大于也可以。
- 用%运算每次取整数的最后一位。
- 用临时变量temp储存这个数据。
- 每次将答案自身*10再加上temp数值。
- 退出循环的条件是 x!=0。
- 判断溢出的思路 :
- 定义不可变量 INT_MAX , INT_MIN。
- 在每次对答案操作之前进行判断
- 如果答案大于max/10或者小于min/10,表示前几位已经比规定值大,此时无论temp数值是多少都会溢出(提前一位开始判断)。
- 如果答案与max或者min数值相等,判断最后一位大小。
- 注意负数取余后仍然是负数。
Third Code
题目
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。
示例 :
输入:x = 121
输出:true
输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。
输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。
解法
自己的解法
class Solution(object):
def isPalindrome(self, x):
if x<0 :
return False
ini=x
ans=0
while(x!=0) :
temp=x%10
ans=ans*10+temp
x//=10
if ans==ini :
return True
else :
return False
与上题的思路基本相同,反转后判断与原数据是否相等。
标准答案
方法一
class Solution(object):
def isPalindrome(self, x):
if x<0 or (x%10==0 and x!=0) :
return False
rev=0
while x>rev :
rev=rev*10+x%10
x//=10
return x==rev or x==rev//10
主要是对之前的思路进行了优化操作
- 判断
- 如果是负数,则一定不是回文。
- 如果是末位为零的数,只有零满足条件。
- 循环优化
- 只需要得出一半的数的rev,可以把这个数与原来的x比较(x在每次循环中减少一位),得出的数要么与x相同位数 要么比x小一位。
- 这时候只用比较x和rev是否相等或者x与rev//10相等即可。
方法二
class Solution(object):
def isPalindrome(self,x) :
return str(x) == str(x)[::-1]
利用字符串反转做,但耗时较长。
Fourth Code
题目
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 | 数值 |
---|---|
I | 1 |
V | 5 |
X | 10 |
L | 50 |
C | 100 |
D | 500 |
M | 1000 |
例如, 罗马数字 2 写做 II ,即为两个并列的 1。
12 写做 XII ,即为 X + II 。
27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。
但也存在特例,例如 4 不写做 IIII,而是 IV。
数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。
同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
-
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
-
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
-
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 1:
输入: “III”
输出: 3
示例 2:
输入: “IV”
输出: 4
示例 3:
输入: “IX”
输出: 9
示例 4:
输入: “LVIII”
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:
输入: “MCMXCIV”
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
解法
自己的解法
class Solution(object):
def romanToInt(self, s):
L=[]
ans=0
for x in s :
L.append(x)
for i in range (0, len(L)) :
if L[i]=='I' :
ans+=1
elif L[i]=='V' :
if i>0 and L[i-1]=='I' :
ans+=3
else :
ans+=5
elif L[i] == 'X':
if i > 0 and L[i - 1] == 'I':
ans += 8
else:
ans+=10
elif L[i] == 'L':
if i > 0 and L[i - 1] == 'X':
ans += 30
else:
ans+=50
elif L[i]=='C' :
if i > 0 and L[i - 1] == 'X':
ans += 80
else:
ans += 100
elif L[i]=='D' :
if i > 0 and L[i - 1] == 'C':
ans += 300
else:
ans += 500
elif L[i]=='M' :
if i > 0 and L[i - 1] == 'C':
ans += 800
else:
ans += 1000
return ans
算是硬解,不算很美观,追求美观的话可以考虑把连续的意义不同的字符替换成别的字符表示。
标准答案
class Solution(object) :
def romanToInt(self, s):
dict={'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
sum=0
pre=dict[s[0]]
for x in range(1,len(s)) :
if dict[s[x]]>dict[s[x-1]] :
sum-=pre
else :
sum+=pre
pre=dict[s[x]]
sum+=pre
return sum
- 利用dict表示字母与数字的对应关系 这样就可以用下标来访问。
- 循环中判断上一个数字和本数字的大小 来决定上一个数字是加还是减
- 最后一个数字无需判断,直接加。
Fifth Code
题目
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入:strs = [“flower”,“flow”,“flight”]
输出:“fl”
示例 2:
输入:strs = [“dog”,“racecar”,“car”]
输出:""
解释:输入不存在公共前缀。
解法
自己的解法
class Solution(object):
def longestCommonPrefix(self, strs):
min=len(strs[0])
for s in strs :
if len(s)<min :
min=len(s)
n=0
flag=True
for i in range(min) :
pre=s[i]
for s in strs :
if s[i]!=pre :
flag=False
break
if flag==False :
break
n+=1
return strs[0][:n]
注意break外层循环的方法
- 利用标志变量flag 。
- 利用return将循环部分写成函数。
- for…else 语句
- 当迭代对象完成所有迭代后且此时的迭代对象为空时,如果存在else子句则执行else子句,没有则继续执行后续代码(仅一次)。
- 如果迭代对象因为某种原因(如带有break关键字)提前退出迭代,则else子句不会被执行,程序将会直接跳过else子句继续执行后续代码。
标准答案
方法一 :横向扫描
class Solution(object) :
def CommonPrefix(self, str1,str2):
len=min(str1,str2)
index=0
while index<len and str1[index]==str2[index] :
index+=1
return str1[0,index]
def longestCommonPrefix(self,strs):
if len(strs)==0 :
return ""
prefix=strs[0]
count=len(strs)
for i in range (count) :
prefix= self.CommonPrefix(prefix, strs[i])
if len(prefix)==0 :
break
return prefix
用
L
C
P
(
S
1
,
S
2
.
.
.
S
n
)
LCP(S_1,S_2...S_n)
LCP(S1,S2...Sn)表示字符串
S
1
.
.
.
S
n
S_1...S_n
S1...Sn的最长公共前缀,可以得到:
L
C
P
(
S
1
,
S
2
.
.
.
S
n
)
=
L
C
P
(
L
C
P
(
L
C
P
(
S
1
,
S
2
)
,
S
3
)
,
.
.
.
S
n
)
LCP(S_1,S_2...S_n)=LCP(LCP(LCP(S_1,S_2),S_3),...S_n)
LCP(S1,S2...Sn)=LCP(LCP(LCP(S1,S2),S3),...Sn)
方法二:纵向扫描(和自己的方法思路差不多)
class Solution :
def longestCommonPrefix(self,strs):
if not strs:
return ""
len,count=len(strs[0]),len(strs)
for i in range(len) :
c=strs[0][i]
if any(i==len(strs[j]) or strs[j][i]!=c for j in range(1,count)) :
return strs[0][:i]
return strs[0]
- 直接使用第一个字符串来比较,而自己的方法是找到最短的字符串比较,相比之下自己的方法时间复杂度比较长。
- 语言简洁
if not strs
判断条件可以直接判断字符list是否为空if any(i==len(strs[j]) or strs[j][i]!=c for j in range(1,count))
- 首先是个循环结构,
for j in range(1,count))
表示从字符串list第二个开始比较 i==len(strs[j]) or strs[j][i]!=c
当循环下标大于当前字符串下标或者当前字符串下标对应字母值与期望不相等时,退出循环- 此时的i是第一个不符合条件的,切片的时候
[0:i]
恰好取不到这个 - 切片操作
- 首先是个循环结构,