算法设计-Python编程 (2) 数组,哈希表,动态规划(字符串翻译,风景评分)

主要做一些想法的总结

1. 两数之和

哈希表传送门: 哈希表

① 暴力解法

用两层循环,循环获取数据,但会重复读取数据,所以我们需要从第一个和第二个数据开始,并且不要直接读取列表

用下标作为循环的变量,依据下标循环读取列表

在第二个循环使用 第一个循环的下标值+1 作为标准,就能很好的契合我们一组一组比对过去的需求

记得在得到数据后,输出 return i,j 并且 break .若没找到,使用 else: continue 进行再循环

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i+1,n):
                if nums[i]+nums[j] == target:
                    return i,j
                    break
                else:
                    continue

② 用 if 判断替代一个 for 循环

第一步一样,也是使用 for 取出下标,再取出数据

第二步 用 target 减去 数值,再用 if ,,

  将差值与剩下的数做对比,若一样再用 index() 函数获取该数值的下标,

      若下标与第一步的下标一致,则 continue ,因为不能重复.

      若不一样,则跳过该次循环

  若不一样,跳过该次循环

(D_value :差值  key:下标 ) 耗时是上面的 1/6,内存差不多

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            D_value=target-nums[i]
            if D_value in nums:
                key = nums.index(D_value)
                if key==i:
                    continue
                else:
                    return i,key
            else:
                continue

③ 哈希表

主要是将数组的内容与下标交换,并转化为字典,将 value 作为 key ,index 作为 字典值

利用字典的优势进行优化

先新建一个空的字典, hashmap = {}

使用 enumerate 函数处理 nums 数组,使每个值前带上 index

并从中取出 indx 和 num

用目标值减去 num,并检查是否存在于 hashmap 中

若存在,返回

若不存在,则 赋予 {num: idx} 到 hashmap 中

 

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashmap = {}
        for idx, num in enumerate(nums):
            if target - num in hashmap:
                return [hashmap[target - num],idx]
            else:
                hashmap[num] = idx

 

2. 把数字翻译成字符串

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

遇到动态规划的题,直接考虑把结果全部算出来是比较难以做到的,一般考虑递推的办法,也就是只考虑所在存在的可能性,根据当前的可能性,不断的循环递归自身,最终求出结果.

那我们只考虑当前的话,那只有两个结果,这个数字和前一个数字可以一起翻译,这个数字和前一个数字不能一起翻译.

假设,当前数字,连续两个数字一起翻译,则剩下的数字的翻译方案数为 f(i-2),单独翻译则剩下的为 f(i-1)

则在当前位置,翻译的方案数为 f(i-2)+f(i-1),即当前翻译一个或者两个,剩下的数字的方案数加起来

若当前位置只能被单独翻译,则方案数与该位置的数字无关,则该位置的方案数等于 i-1 的方案数

设定当前状态:动态规划表 dp,dp[i] 代表以 xi 为结尾的数字的翻译方案数量

若当前可被翻译则,dp[i] = dp[i-1] + dp[i-2],否则 dp[i] = dp[i-1]

再确定一下哪些数字可以被两位数翻译,是 [10,25]

那可不可翻译的条件就可以设定为   与   

我们可以从右往左,也可以从左往右,这里使用从右往左,比较契合上面的题解

方法一:字符串遍历

时间复杂度和空间复杂度均为 N

时间复杂度的 N  为字符串 s 的长度,决定了循环次数

空间复杂度为 字符串 s 使用的大小

首先

将数字转化为字符串,str()

设定初始变量 a=b=1

循环次数为 range(len(s)-2,-1,-1)

意思为 s 的长度 减2开始,到 -1 的前一个数字,也就是0.每次步幅为 -1

用例子说明比较形象,比如这里就是

12258

那 i 一开始就是 3,也就是说一开始在识别 i与i+1 是否能组合,,也就是第四位数字和第五位数字

至于为什么要减2 ,主要是一个是位数是从 0 开始的,还有就是长度会比 s 的位数也多一

这里设定公式:

a,b ,a为 f(i)   b为f(i-1)

拆开循环算一下, 

i = 3,  a = 1,s[i:i+2]=58,  b = 1

i = 2 ,a = a+b = 2,s[i:i+2] = 25,b = a =1

i = 1,a = a+b=3,s[i:i+2]=22,b=a=2

i=0,a = a+b=5,s[i:i+2]=12,b =a =3

相当于在循环中完成了对 a b 的递归

class Solution:
    def translateNum(self, num: int) -> int:
        s = str(num)
        a = b = 1
        for i in range(len(s) - 2, -1, -1):
            a, b = (a + b if "10" <= s[i:i + 2] <= "25" else a), a
        return a

 

3. 最佳观光组合

给定正整数数组 A,A[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的距离为 j - i。

一对景点(i < j)组成的观光组合的得分为(A[i] + A[j] + i - j):景点的评分之和减去它们两者之间的距离。

返回一对观光景点能取得的最高分

输入:[8,1,5,2,6]
输出:11
解释:i = 0, j = 2, A[i] + A[j] + i - j = 8 + 5 + 0 - 2 = 11

这个其实也是动态规划,按照前面的思路,动态规划,只考虑当下,才能降低运算的复杂度

看了题目,max()应该是对状态进行改变的一个很好地函数

最先想到的自然是双层 for 循环,一个一个找过去,不过这样明显就是最慢的办法,我们再观察一下分数的计算公式

A[i]+A[j] +i -j ,可以分为两个部分,A[i]+i 为一个部分,A[j]-j 为一个部分,第一个部分有什么特点呢,也就是说 A[i]+i的值是有两部分组成的,一个是位置所在的值,一个是越往后越大.

那我们看一下两层 for 循环的暴力解法

class Solution:
    def maxScoreSightseeingPair(self, A: List[int]) -> int:
        num_max=A[0]+A[1]-1
        for i in range(len(A)):
            for j in range(i+1,len(A)):
                num_max=max(num_max,A[i]+A[j]+i-j)
        return num_max

但我们发现,

比如第一次循环 i 固定为 0,j在 【1,len(A)-1】中变动,

这个时候 A[i] + i 是固定的,而A【j】-j 求的就是后面所有值中的最大值,

那我们如何用这一点来优化我们的函数呢,

也就是说,我们只需要遍历 j ,然后 j 每取一个值,他前面的 i,直接取 i 中的最大值即可,也就是 A【i】+i 的最大值。(当然,你遍历 i ,然后取 A[J]-J 的最大值,好像也行,不过这里采取遍历 i 的办法)

既然我们要遍历 j,那我们就需要从 1 开始

那 max(A[i]+i) 的初始值可以初始化为 A[0]+0 

max_value=A[0] + 0

总体的值初始化为 0

ans = 0

对 j 进行循环遍历

for j in range(1,len(A)):
    # 这一步就是更新评分值,对比之前的评分,取高评分
    ans = max(ans,max_value+A[j]-j)
    # 这里虽然写着 A[j]+j 但实际上在题目中代表着,A[i]+i,因为放在了评分后面,所以直接使用 A[j]+j 即可
    max_value = max(max_value,A[j]+j)

return ans
class Solution(object):
    def maxScoreSightseeingPair(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        res = 0
        pre_max = A[0] + 0 #初始值
        for j in range(1, len(A)):
            res = max(res, pre_max + A[j] - j) #判断能否刷新res
            pre_max = max(pre_max, A[j] + j) #判断能否刷新pre_max, 得到更大的A[i] + i
                
        return res

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值