如何正确地记住这个LIS python2.7算法?

时间:2016-10-12 08:03:03

标签: python algorithm dynamic-programming memoization

我正在练习动态编程,而且我正在编写最长的后续子序列问题。

我有DP解决方案:

export function addTab(name, icon) {
  return (dispatch) => {
    dispatch({ type: 'TABS_POST_START' });
    return axios({
      method: 'POST',
      url: '/rest-api/ui/tabs/',
      headers: {
        'X-CSRFToken': CSRF_TOKEN,
        'Content-Type': 'application/json'
      },
      data: {
        name,
        icon
      },
    })
    .then((response) => {
      dispatch({ type: 'TABS_POST_SUCCESS' });
      dispatch({ type: 'TABS_ADD', tab: response.data });
    })
    .catch((err) => {
      dispatch({ type: 'TABS_POST_FAILURE', payload: err });
    });
  };
}

export function fetchTabs() {
  return (dispatch) => {
    dispatch({ type: 'TABS_FETCH_START' });
    return axios.get('/rest-api/ui/tabs/')
      .then((response) => {
        dispatch({ type: 'TABS_FETCH_SUCCESS' })
        dispatch({ type: 'TABS_SET', tabs: response.data });
      })
      .catch((err) => {
        dispatch({ type: 'TABS_FETCH_FAILURE', payload: err });
      });
  };
} 

一个非记忆版

def longest_subsequence(lst, lis=[], mem={}):
  if not lst:
    return lis
  if tuple(lst) not in mem.keys():
    if not lis or lst[0] > lis[-1]:
      mem[tuple(lst)] = max([longest_subsequence(lst[1:], lis+[lst[0]], mem), longest_subsequence(lst[1:], lis, mem)], key=len)
    else:
     mem[tuple(lst)] = longest_subsequence(lst[1:], lis, mem)
  return mem[tuple(lst)]

但是,这两个功能有不同的行为。例如,测试用例def longest_subsequence(lst, lis=[]): if not lst: return lis if not lis or lst[0] > lis[-1]: result = max([longest_subsequence(lst[1:], lis+[lst[0]]), longest_subsequence(lst[1:], lis)], key=len) else: result = longest_subsequence(lst[1:], lis) return result 对于memoized版本失败。

longest_subsequence([10,9,2,5,3,7,101,18])

然而,非记忆版本完全正确(虽然慢得多)。

>>> longest_subsequence([10,9,2,5,3,7,101,18])
[10, 101]

我做错了什么?

编辑: Tempux的答案在以下方面失败:

>>> longest_subsequence([10,9,2,5,3,7,101,18])
[2, 5, 7, 101]

非记忆版本的解决方案是:

>>> longest_subsequence([3,5,6,2,5,4,19,5,6,7,12])
[3, 5, 6, 7, 12]

2 个答案:

答案 0 :(得分:4)

您的州取决于lst和之前选择的项目。但你只考虑lst。这就是为什么你得到不正确的结果。要解决此问题,您只需将上一项添加到动态状态即可。

def longest_subsequence(lst, prev=None, mem={}):
  if not lst:
    return []
  if (tuple(lst),prev) not in mem:
    if not prev or lst[0] > prev:
      mem[(tuple(lst),prev)] = max([[lst[0]]+longest_subsequence(lst[1:], lst[0]), longest_subsequence(lst[1:], prev)], key=len)
    else:
     mem[(tuple(lst),prev)] = longest_subsequence(lst[1:], prev)

  return mem[(tuple(lst),prev)]

print longest_subsequence([3,5,6,2,5,4,19,5,6,7,12])

请注意,使用tuple(list)作为动态状态并不是一个好主意。您只需使用您正在检查的list中的项目索引而不是整个列表:

def longest_subsequence(lst, index=0, prev=None, mem={}):
  if index>=len(lst):
    return []
  if (index,prev) not in mem:
    if not prev or lst[index] > prev:
      mem[(index,prev)] = max([[lst[index]]+longest_subsequence(lst, index+1, lst[index]), longest_subsequence(lst, index+1, prev)], key=len)
    else:
      mem[(index,prev)] = longest_subsequence(lst,index+1, prev)

  return mem[(index,prev)]

print longest_subsequence([3,5,6,2,5,4,19,5,6,7,12])

要获得更有效的方法,您可以查看this问题。

答案 1 :(得分:0)

所以我刚刚发现Tempux的答案并不适用于所有情况。

我回过头来将整个状态封装到memoization字典中,从而添加了tuple(lis)作为密钥的一部分。此外,lst索引技巧可能不容易实现,因为我通过递归变异lst,因此我使用tuple()作为我的键。

我所做的背后的原因是多个lis可能具有相同的[-1]值。因此,使用这个新状态,代码是:

def longest_subsequence(lst, lis=[],mem={}):
  if not lst:
    return lis
  if (tuple(lst),tuple(lis)) not in mem:
    if not lis or lst[0] > lis[-1]:
      mem[(tuple(lst),tuple(lis))] = max([longest_subsequence(lst[1:], lis+[lst[0]]), longest_subsequence(lst[1:], lis)], key=len)
    else:
     mem[(tuple(lst),tuple(lis))] = longest_subsequence(lst[1:], lis)
  return mem[(tuple(lst),tuple(lis))]

这适用于我目前测试过的所有情况。