Python算法之简单题(1-10)

题目来源于 https://leetcode-cn.com/

1、两数之和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。

你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

示例

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

Python代码:

def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        compliments = {}
        for i in range(len(nums)):
            if nums[i] in compliments:
                return [compliments[nums[i]], i]
            comp = target - nums[i]
            compliments[comp] = i

2、反转整数

给定一个 32 位有符号整数,将整数中的数字进行反转。

示例 1:

输入: 123
输出: 321

 示例 2:

输入: -123
输出: -321

示例 3:

输入: 120
输出: 21

注意:

假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231,  231 − 1]。根据这个假设,如果反转后的整数溢出,则返回 0。

Python代码:

 def reverse(self, x):
        """
        :type x: int
        :rtype: int
        """
        cmp=lambda a,b: (a>b)-(a<b)  ##根据cmp判断x是正数还是负数
        s=cmp(x,0)
        rev=int(str(s*x)[::-1]) #把结果都处理为正数,[::-1]是列表倒序,在这里是是对正整数进行倒序
        return s*rev*(rev<2**31-1) if s>0 else s*rev*(rev<2**31)  #处理溢出,并根据s的取值(-1,或1)来确定正负号。
        

 3、回文数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例1:

输入:121 

输出:true

示例2:

输入:-121

输出:false

实例2解释:从左向右读,为-121,从右向左读,为121-,因此不是一个回文数。

示例3:输入10

输出:false

Python代码:

def isPalindrome(x):
    s=str(x)
    if s[::-1] == s:  #翻转后与原字符串比较
        return True
    return False

4、罗马数字转整数

罗马数字包含以下七种字符: I, V, X, LCD 和 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.

Python代码:

def romanToInt(s):
    rom_to_int = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
    result = 0
    num = 3999
    for i in s:
        t = rom_to_int[i]  
        if t<= num:   #通常情况下,罗马数字中小的数字在大的数字的右边
            num = t
        else:
            num = -2*num + t #特殊情况,这种情况的数学定义隐含很深
        result += num
     return result
'''
总结:
给定任意的罗马数字字符串,理想情况(第i个字符字符代表的值比第i+1的大)都是从左往右依次相加就行(只执行上述中的if)。
但是如果遇到了特殊情况,比如第i个字符代表的数字比第i+1代表的小(出现特殊情况),
那么通过(-2*num+t)就可以让第i+1个字符代表的数字临时改变,使第i、第i+1两个字符组合的罗马数字的值符合6种特殊情况的值(这一点很难想到)

思考:
特殊情况下-2*num+t 为什么能保持num在下一轮的循环里if或else正确?而不会出现num值变大或者变小的情况?

'''
print(romanToInt("M"))

5、最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""

示例 1:

输入: ["flower","flow","flight"]
输出: "fl"

示例 2:

输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。

说明:

所有输入只包含小写字母 a-z 。

Python代码:

import itertools

def longestCommonPrefix(strs):
    """
    参数:List
    返回值: str
    """
    prefix = ""
    for chars in itertools.zip_longest(*strs):
        ##chars类型为元组,就像这样('h', 'h', 'h'),通过类型转换来变成set去重
        if len(set(chars)) == 1: ##set去重后若等于1,说明存在一个共同字符
            prefix += chars[0]
        else:
            return prefix
		
print(longestCommonPrefix(["hello","he","hel"]))

'''
**************************************************************
知识点一:
itertools模块: 提供了用于操作迭代对象的一系列函数。
和内置的zip模块功能类似(一一对应),不过zip是以元素最少的对象为准,而zip_longest是以元素最多的对象为标准,使用fillvalue来填充。

example:
res = zip_longest('abc', '12')
for x in res:
  print(x)

结果:
('a', '1')
('b', '2')
('c', None)
*****************************************************************
知识点二:
zip_longest的参数*strs。
因为传入的值是一个列表,不能对其直接做zip_longest操作,加*能将列表解开成独立的参数。
就相当于 itertools.zip_longest("hello","he","hel"),这种参数也符合zip_longest参数特征。
        
'''

6、有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"
输出: true

示例 2:

输入: "()[]{}"
输出: true

示例 3:

输入: "(]"
输出: false

示例 4:

输入: "([)]"
输出: false

示例 5:

输入: "{[]}"
输出: true

Python代码:

def isValid(s):
	"""
    :type s: str
    :rtype: bool
     """
	list=[]
    for c in s:
        if c == '(':
            list.append('(')
        elif c == ')':
            if not list or list.pop() != '(':
                return False
        elif c == '[':
            list.append('[')
        elif c == ']':
             if not list or list.pop() != '[':
                return False
        elif c == '{':
             list.append('{')
        elif c == '}':
             if not list or list.pop() != '{':
                return False
    if list:
        return False
    else:
        return True
			
print(isValid("{}()[])"))

'''
*************************************************************
上述实现方法是最直接易懂的,不像算法4有一个骚操作,但很多地方可以改进。

思想:栈结构
1、如果遇到三种任意左括号,则append入栈。
2、如果遇到一种右括号,则判断list是否为空或者list的最后一个元素是否为这种右括号对应的左括号。
   因为如果list为空,说明此时来的右括号匹配不到左括号,返回False。如果pop最后的一个元素不为其对
   应的左括号,也说明不匹配。
3、如果中间的这些过程都完美匹配了,即for循环里面的return False都没有执行。则在循环结束时判断list是否为空,为空说明每一个左括号的append有其对应的右括号pop,导致list空,返回True。不为空说明list里面至少残留一个左括号没有匹配的右括号。 
'''

7、删除排序数组中的重复项

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:

给定数组 nums = [1,1,2], 

函数应该返回新的长度 2, 并且原数组nums的前两个元素被修改为 1, 2。 

你不需要考虑数组中超出新长度后面的元素。

示例 2:

给定 nums = [0,0,1,1,1,2,2,3,3,4],

函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。

你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

Python代码:

def removeDuplicates( nums):
    """
     参数:List
     返回值:int
    """
    i = 0
    if nums:
       for j in range(1,len(nums)):
           if nums[i] != nums[j]:
              nums[i+1], nums[j] = nums[j], nums[i+1]   ##python中两个值交换
              i = i + 1
        print(nums)
        return i+1
     else:
        return 0
print(removeDuplicates([1,2,2,3,4,4,5]))

'''
这个解法觉得还是有点难理解
*****************************************************************
骚操作补充:
如果只考虑返回值的正确性的话,考虑快速将其去重并排序

nums=[1,2,2,3,3,4,5]
print(len(sorted(list(set(nums)))))
print(sorted(list(set(nums))))

输出结果:5
叔叔结果:[1,2,3,4,5]
#先set去重,再list转换成适合sorted的类型,再sorted排序。
'''

8、移除元素

给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

给定 nums = [3,2,2,3], val = 3,

函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。

你不需要考虑数组中超出新长度后面的元素。

示例 2:

给定 nums = [0,1,2,2,3,0,4,2], val = 2,

函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

注意这五个元素可为任意顺序。

你不需要考虑数组中超出新长度后面的元素。

Python3代码

def removeElement(nums,val):
   '''
    :type nums: List[int]
    :type val: int
    :rtype: int
   '''
    while val in nums:
        nums.remove(val)  #因为不需要考虑超出新长度后面的元素,所以可以用用remove使整个list长度变短
    return nums

print(removeElement([0,1,2,2,3,0,4,2],2))

'''
**************************************************
总结:
如果使用java之类的语言实现的,我自己首先想到的是把等于val的元素放到后面去。
但是python中的list的remove方法,刚好也能满足条件,而且还不用考虑超出新长度的那些元素,所以等于val的元素在新list中可有可无,而python中刚好是无。
'''

9、实现strStr()

实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回  -1

示例 1:

输入: haystack = "hello", needle = "ll"
输出: 2

示例 2:

输入: haystack = "aaaaa", needle = "bba"
输出: -1

说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

Python3代码:

def strStr(h, n): 
    """
    :type haystack: str
    :type needle: str
    :rtype: int
    """
    if len(n) == 0:
        return 0
    return int(len(h.split(n)[0])) if len(h.split(n)[0])!=len(h) else -1

print(strStr("aaaaa","ba"))

'''
总结:
通过split,得到的结果是和目标子串不一样的子串列表。
如果第一个子串列表的元素[0]长度刚好等于h的长度,说明整个字符串h没有匹配到分割符n,导致子串列表只有一个元素,即h本身。
如果子串列表的第一个元素长度不等于h的长度,那么一定刚好第一个子串(下标0的元素)的长度就是第一次出现目标子串的下标,即目标返回值。
(split后的列表中,第一个子串长度len=第一个子串最后字符下标值+1=目标(n)的下标)
'''

10、搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5
输出: 2

示例 2:

输入: [1,3,5,6], 2
输出: 1

示例 3:

输入: [1,3,5,6], 7
输出: 4

示例 4:

输入: [1,3,5,6], 0
输出: 0

Python3代码:

def searchInsert(nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: int
    """
    for index in range(len(nums)):
        if nums[index] >= target:
            return index
        elif index == len(nums) - 1:
            return len(nums)
    return 0
	
print(searchInsert([1,2,3,3,3,4,4,5],3))

'''
******************************8
总结:
从左往右,如果遇到一次nums[index]>=value,说明找到了位置,可以停止循环,刚好插入在index位置,返回index。
如果没遇到nums[index]>=value,说明循环应该继续往右走,并且如果走到末尾位置,即index=len(nums)-1,
说明应该插入在原列表的最后位置,即下标=len(nums)
'''

猜你喜欢

转载自blog.csdn.net/qq_31371757/article/details/83578297