[python][算法][CS61a]不使用python内置数据类型(字典、列表)也能实现键值对的存储与查询吗?

提示:本文内容来源于UCB CS61A 2020 Summer课程,详情请点击CS 61A: Structure and Interpretation of Computer Programs

前言

本文为2020 Summer UCB CS61a 课程 Diagnostic Quiz 内容


提示:以下是本篇文章正文内容,叙述部分参考题目描述,由本人与chatgpt共同翻译,思路部分及作业部分为作者完成,仅供参考,若有错误欢迎评论指正

Diagnostic Quiz

Key Value Store

Key Value Store 题目描述

A lens store is a store that associates keys with values.

To create a lens store, call the function lens, to get a put function.
This function enables you to put a key-value pair into the store, and returns two functions get and another put.
The get function should let you look up a key and return its corresponding value, while the new put function should let you continue adding on to the existing lens store.

Note that you can assume that every key provided is unique. If you try to get the value for a key that does not exist, return 0.

For details, refer to the doctest.

翻译如下

一个lens存储器是一个将键与值关联起来的存储器。

要创建一个镜头存储器,请调用函数lens来获取一个put函数。

put函数将键值对放入存储器中,并返回两个函数get和另一个put

get函数应该让您查找一个键并返回其对应的值,而新的 put函数应该让您继续添加到现有的lens存储器中。

注意,假设提供的每个键都是唯一的。
若尝试获取不存在的键所对应的值,则返回0。

Key Value Store doctest

"""
>>> put1 = lens()
>>> get2, put2 = put1('cat', 'animal')
>>> get3, put3 = put2('table', 'furniture')
>>> get4, put4 = put3('cup', 'utensil')
>>> get5, put5 = put4('thesis', 'paper')
>>> get5('thesis')
'paper'
>>> get5('cup')
'utensil'
>>> get5('table')
'furniture'
>>> get5('cat')
'animal'
>>> get3('cup')
0
"""

Key Value Store 代码框架

def lens(prev=lambda x: 0):
    def put(k, v):
        def get(k2):
            if _____:
                _____
            else:
                _____
        return _____
    return _____

Key Value Store 解题思路

根据doctest我们可以先观察以下返回值

首先是整个lens函数的返回值,根据

>>> put1 = lens()

操作,我们可以知晓lens应返回put函数

def lens(prev=lambda x: 0):
    def put(k, v):
        def get(k2):
            if _____:
                _____
            else:
                _____
        return _____
    return put

根据以下doctest和题目描述,我们可以知晓put函数的返回值应为一个get函数,一个新的put函数,而由于get函数是在put函数中定义,因此直接返回put, get肯定只会得到一个NameError,但是根据题目描述中put函数想要返回一个“新”的put函数,再加上lens函数的返回值是put,因此我们只返回对lens函数的递归调用(暂时将其参数空出)

>>> get2, put2 = put1('cat', 'animal')
>>> get3, put3 = put2('table', 'furniture')
>>> get4, put4 = put3('cup', 'utensil')
>>> get5, put5 = put4('thesis', 'paper')
def lens(prev=lambda x: 0):
    def put(k, v):
        def get(k2):
            if _____:
                _____
            else:
                _____
        return get, lens(<param: unkown function>)
    return put

观察如下doctest

>>> get5('thesis')
'paper'
>>> get5('cup')
'utensil'
>>> get5('table')
'furniture'
>>> get5('cat')
'animal'
>>> get3('cup')
0

我们发现与函数get5可以获取其put4及其之前导入的所有键对值,如下我们模拟一下get5('thesis')所在的环境

def lens(prev=<param: unkown function>):
    def put4(k='thesis', v='paper'):
        def get5(k2='thesis'):
            if _____:
                _____
            else:
                _____
        return get, lens(<param: unkown function>)
    return put

发现k2k是相等的,因此get5只需要在当前的lens中查找即可

def put4(k='thesis', v='paper'):
    def get5(k2='thesis'):
        if k2 == k:
            return v
        else:
            _____
    return get, lens(<param: unkown function>)

如果在当前lensk2k不等

>>> get5('cup')
'utensil'
>>> get5('table')
'furniture'
>>> get5('cat')
'animal'

那么就需要查找之前put的键值对,因此我们需要在当前lens中拥有get之前value的接口

再结合给出的代码框架def lens(prev=lambda x: 0):中,lens函数的参数prev是一个隐藏的提示,我们可以通过这个参数在前一个lens中查找想要的key所对应的value值,如下

def put4(k='thesis', v='paper'):
    def get5(k2='thesis'):
        if k2 == k:
            return v
        else:
            return prev(k2)
    return get5, lens(<param: unkown function>)

为了达到目的,prev可以查询上一个lens中的内容,因此我们put函数的return语句调用lens时,应该把当前的get传入lens的参数当中,如下

def lens(prev=lambda x: 0):
    def put(k, v):
        def get(k2):
            if k2 == k:
                return v
            else:
                return prev(k2)
        return get, lens(get)
    return put

至于题目中要求没有的键对值返回零,只要查询到第一个创建的lens,由于k2k仍然不等,所以进入else语句继续向前查询

但是put1 = lens(),这个lens中没有传入任何参数,因此prev就是default value,即lambda x: 0,返回0值,符合题目要求

doctest中的代码转换为非递归形式可以方便理解,可能有错误仅供参考

def lens1(prev=lambda x: 0):
    def put1(k='cat', v='animal'):
        def get2(k2):
            if k2 == k:
                return v
            else:
                return prev(k2)
        return get2, lens2(get2)
    return put1

def lens2(prev=get2):
    def put2(k='table', v='furniture'):
        def get3(k2):
            if k2 == k:
                return v
            else:
                return prev(k2)
        return get3, lens3(get3)
    return put2

def lens3(prev=get3):
    def put3(k='cup', v='utensil'):
        def get4(k2):
            if k2 == k:
                return v
            else:
                return prev(k2)
        return get4, lens4(get4)
    return put3

def lens4(prev=get4):
    def put4(k='thesis', v='paper'):
        def get5(k2):
            if k2 == k:
                return v
            else:
                return prev(k2)
        return get5, lens5(get5)
    return put4

测试通过

$ python3 -m doctest key_value_store.py -v
Trying:
    put1 = lens()
Expecting nothing
ok
Trying:
    get2, put2 = put1('cat', 'animal')
Expecting nothing
ok
Trying:
    get3, put3 = put2('table', 'furniture')
Expecting nothing
ok
Trying:
    get4, put4 = put3('cup', 'utensil')
Expecting nothing
ok
Trying:
    get5, put5 = put4('thesis', 'paper')
Expecting nothing
ok
Trying:
    get5('thesis')
Expecting:
    'paper'
ok
Trying:
    get5('cup')
Expecting:
    'utensil'
ok
Trying:
    get5('table')
Expecting:
    'furniture'
ok
Trying:
    get5('cat')
Expecting:
    'animal'
ok
Trying:
    get3('cup')
Expecting:
    0
ok
1 items had no tests:
    key_value_store
1 items passed all tests:
  10 tests in key_value_store.lens
10 tests in 2 items.
10 passed and 0 failed.
Test passed.

Storeroom

Storeroom 题目描述

Write a function storeroom that takes in a positive integer ‘helium’ and two functions fn_even and fn_odd.

It applies fn_even to all the even digits in the integer and applies fn_odd to all the odd digits in the integer.

It then returns whether the result of the even values is greater than the result of the odd values.

You can guarantee that the number has at least one even and odd digit.

翻译如下

实现一个函数 storeroom,其参数为:一个正整数helium、两个函数fn_evenfn_odd

它将fn_even应用于helium中的所有偶数数字,将fn_odd应用于helium中的所有奇数数字

然后,它返回偶数值的结果是否大于奇数值

输入保证该数字至少有一个偶数位和一个奇数位。

Storeroom doctest

"""
>>> storeroom(1234, lambda x,y: x+y, lambda x,y: x*y) # 4 + 2 > 3 * 1
True
>>> storeroom(11111111111112, lambda x,y: x+y, lambda x,y: x*y) # 2 > 1 * 1 * ... * 1
True
>>> storeroom(11111111111112, lambda x,y: x+y, lambda x,y: x+y) # 2 <= 1 + 1 + ... + 1
False
>>> storeroom(12, lambda x,y: x+y, lambda x,y: x*y) # 2 > 1
True
>>> storeroom(12345, lambda x,y: x+y, lambda x,y: x*y) # 4 + 2 <= 1 * 3 * 5
False
>>> storeroom(18383, lambda x,y: x-y, lambda x,y: x-y) # 8 - 8 > 3 - 3 - 1
True
"""

Storeroom 代码框架

def storeroom(helium, fn_even,fn_odd):
    evens_defined, odds_defined = False, False
    evens, odds = None, None
    while _____:
        _____ = _____
        if _____:
            if _____:
                _____
                _____
            else:
                _____
        else:
            if _____:
                _____
                _____
            else:
                _____
    return evens > odds

Storeroom 解题思路

观察doctest,发现其给的注释中数为均为从右往左计算,如1234,偶数数字计算顺序为4 fn_even 2而忽视2 fn_even 4

依次使用模运算依次取helium的最后一位即可

第一反应是下面这个实现,但是有变量没用上,还有空没填

def storeroom(helium, fn_even,fn_odd):
    evens_defined, odds_defined = False, False
    evens, odds = None, None
    while helium:
        digit, helium = helium % 10, helium // 10
        if digit % 2 == 0:
            if evens != None:
                evens = fn_even(evens, digit)
                # _____
            else:
                evens = digit
        else:
            if odds != None:
                odds = fn_odd(odds, digit)
                # _____
            else:
                odds = digit
    return evens > odds

改一下实现就好

def storeroom(helium, fn_even,fn_odd):
    evens_defined, odds_defined = False, False
    evens, odds = None, None
    while helium:
        digit, helium = helium % 10, helium // 10
        if digit % 2 == 0:
            if evens_defined == False:
                evens_defined = True
                evens = digit
            else:
                evens = fn_even(evens, digit)
        else:
            if odds_defined == False:
                odds_defined = True
                odds = digit
            else:
                odds = fn_odd(odds, digit)
    return evens > odds

测试通过

$ python3 -m doctest storeroom.py -v
Trying:
    storeroom(1234, lambda x,y: x+y, lambda x,y: x*y) # 4 + 2 > 3 * 1
Expecting:
    True
ok
Trying:
    storeroom(11111111111112, lambda x,y: x+y, lambda x,y: x*y) # 2 > 1 * 1 * ... * 1
Expecting:
    True
ok
Trying:
    storeroom(11111111111112, lambda x,y: x+y, lambda x,y: x+y) # 2 <= 1 + 1 + ... + 1
Expecting:
    False
ok
Trying:
    storeroom(12, lambda x,y: x+y, lambda x,y: x*y) # 2 > 1
Expecting:
    True
ok
Trying:
    storeroom(12345, lambda x,y: x+y, lambda x,y: x*y) # 4 + 2 <= 1 * 3 * 5
Expecting:
    False
ok
Trying:
    storeroom(18383, lambda x,y: x-y, lambda x,y: x-y) # 8 - 8 > 3 - 3 - 1
Expecting:
    True
ok
1 items had no tests:
    storeroom
1 items passed all tests:
   6 tests in storeroom.storeroom
6 tests in 2 items.
6 passed and 0 failed.
Test passed.

Maximum Subnumber

Maximum Subnumber 题目描述

Given a number ruler, finds the largest number of length k or fewer, composed of digits from ruler, in order.

翻译如下

给定一个数字ruler,找到由ruler中的数字组成的长度不超过k的最大数字,该数字中的各个输赢按照其在ruler中的出现顺序排列。

Maximum Subnumber doctest

"""
>>> sculptural(1234, 1)
4
>>> sculptural(32749, 2)
79
>>> sculptural(1917, 2)
97
>>> sculptural(32749, 18)
32749
"""

Maximum Subnumber 代码框架

def sculptural(ruler, k):
    if ______________________________:
        return _______________________________
    a = _____________________________
    b = _____________________________
    return _____________________________

Maximum Subnumber 解题思路

个人思路如下:

  • 假设ruler的最后一位在要求的结果中
    • 则要求的数字的个位正好为ruler的最后一位
    • ruler // 10中找到由ruler // 10中的数字组成的长度不超过k - 1的最大数字
    • 将以上二者拼接起来
  • 假设ruler的最后一位不在要求的结果中
    • 抛弃ruler最后一位,在剩余ruler // 10中找到由ruler // 10中的数字组成的长度不超过k的最大数字
  • 比较以上两步的结果,其中较大的那一个就是要求的数字

使用递归函数来完成

def sculptural(ruler, k):
    if k == 0 or ruler == 0:
        return 0
    a = sculptural(ruler // 10, k-1) * 10 + ruler % 10
    b = sculptural(ruler // 10, k)
    return a if a > b else b

递归出口

if k == 0 or ruler == 0:
    return 0

其中,k == 0,表示要求的结果数字位数已经够了,直接返回0,回到k = 1的那一层即可

而 ruler == 0,则表示所有数字已经找过一遍了,但数字位数仍然没有达到要求,由于题目要求结果可以小于给定长度,所以直接返回0即可

以上实现可以通过题目给的几个测试样例

$ python3 -m doctest maximum_subnumber.py -v
Trying:
    sculptural(1234, 1)
Expecting:
    4
ok
Trying:
    sculptural(32749, 2)
Expecting:
    79
ok
Trying:
    sculptural(1917, 2)
Expecting:
    97
ok
Trying:
    sculptural(32749, 18)
Expecting:
    32749
ok
1 items had no tests:
    maximum_subnumber
1 items passed all tests:
   4 tests in maximum_subnumber.sculptural
4 tests in 2 items.
4 passed and 0 failed.
Test passed.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值