Leetcode 526. Beautiful Arrangement

Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is constructed by these N numbers successfully if one of the following is true for the ithposition (1 <= i <= N) in this array:

  1. The number at the ith position is divisible by i.
  2. i is divisible by the number at the ith position.

 

Now given N, how many beautiful arrangements can you construct?

Example 1:

Input: 2
Output: 2
Explanation: 

The first beautiful arrangement is [1, 2]:

Number at the 1st position (i=1) is 1, and 1 is divisible by i (i=1).

Number at the 2nd position (i=2) is 2, and 2 is divisible by i (i=2).

The second beautiful arrangement is [2, 1]:

Number at the 1st position (i=1) is 2, and 2 is divisible by i (i=1).

Number at the 2nd position (i=2) is 1, and i (i=2) is divisible by 1.

 

Note:

  1. N is a positive integer and will not exceed 15.
 1 class Solution:
 2     def DFS(self, N, glist, start, chosen):
 3         if start == N+1:
 4             self.count += 1
 5             return
 6         llist = glist[start-1]
 7         for i,ele in enumerate(llist):
 8             if ele in chosen:
 9                 continue
10             chosen.add(ele)
11             self.DFS(N, glist, start+1, chosen)
12             chosen.discard(ele)
13         return
14     
15     def countArrangement(self, N):
16         """
17         :type N: int
18         :rtype: int
19         """
20         glist = []
21         for i in range(1,N+1):
22             llist = []
23             for j in range(1,i+1):
24                 if i%j == 0:
25                     llist.append(j)
26             for j in range(i+1,N+1):
27                 if j%i == 0:
28                     llist.append(j)
29             glist.append(llist[:])
30         self.count = 0
31         chosen = set()
32         self.DFS(N, glist, 1, chosen)
33         return self.count

 

Above is my solution. First build the candidate list. Then loop thru it using DFS. Each time pick one and solve the rest.

Good: Clear

Bad: This DFS approach can NOT be changed to use memo approach to optimization. In fact, this code can only beat 40% python submissioin on LC

 

 1 cache = {}
 2 class Solution(object):
 3     def countArrangement(self, N):
 4         def helper(i, X):
 5             if i == 1:
 6                 return 1
 7             key = (i, X)
 8             if key in cache:
 9                 return cache[key]
10             total = 0
11             for j in xrange(len(X)):
12                 if X[j] % i == 0 or i % X[j] == 0:
13                     total += helper(i - 1, X[:j] + X[j + 1:])
14             cache[key] = total
15             return total
16         return helper(N, tuple(range(1, N + 1)))

The above approach presented by zhongyuan9817 here: https://leetcode.com/problems/beautiful-arrangement/discuss/99717/Python-recursion-%2B-DP-66ms

is better in that: 1) it's cacheable/Memorizable; 2) It select the eligible list on the fly!

How he achieved this? First, reduce the problem size N -> N-1; Second, in the reduced the size of problem, pick ONE out that's valid for this ith position, and then

recurse to the smaller problem. 

虽然同样是DFS,但是答案的构造方向是不一样的!我所使用的是从上到下,必须全程走一遍才能得到答案,不利于Memorization!zhongyuan9817 提供的DFS的答案是从下而上

构造出来的,可以用记忆化方法加速!这个区别应该理解和注意!

 

posted @ 2019-03-02 13:59  ucode  阅读(162)  评论(0编辑  收藏  举报