挑戰LeetCode Weekly Contest 49

2017-09-10
程式解題/ LeetCode

三度挑戰

這次的題目,前兩題真的簡單,至於後兩題,真心難QQ ,最終成績 753 / 2362。


第1題 674. Longest Continuous Increasing Subsequence

問題

給一個未排序的整數陣列,找出最長的連續遞增子序列的長度。

輸入範例 1

[1,3,5,4,7]

輸出範例 1

3

輸入範例 2

[2,2,2,2,2]

輸出範例 2

1

方法

遞增序列的特性就是較晚出現的元素一定大於較先出現的元素,遍歷整個陣列,因為要求為「連續」,所以只要遇到不符合遞增條件的元素,就要重新計算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution(object):
def findLengthOfLCIS(self, nums):
if not nums:
return 0
maximum = 1
current = 1
for i in range(1, len(nums)):
if nums[i - 1] < nums[i]:
current += 1
else:
maximum = max(maximum, current)
current = 1
maximum = max(maximum, current)
return maximum

第2題 676. Implement Magic Dictionary

問題

定義一個陣列,由許多字串組成,輸入一個字串,若陣列中任一字串更改一個字母後,與輸入的字串相同,回傳True,反之則回傳False

輸入與輸出

Input: buildDict(["hello", "leetcode"]), Output: Null
Input: search("hello"), Output: False
Input: search("hhllo"), Output: True
Input: search("hell"), Output: False
Input: search("leetcoded"), Output: False

方法

這題沒有什麼特殊的技巧,只要將輸入字串與陣列內的字串一一比對即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MagicDictionary(object):

def __init__(self):
self.magic = []


def buildDict(self, dic):
self.magic = dic


def search(self, word):
for m in self.magic:
modify = 0
if len(m) == len(word):
for i in range(len(m)):
if m[i] != word[i]:
modify += 1
if modify == 1:
return True
return False
## 第3題 675. Cut Off Trees for Golf Event ##
### 問題 ### 輸入一個二維陣列,0代表無法通過的障礙物,1代表可以通行的草皮,大於1的數代表一棵樹,同樣可以通行,數字大小代表樹的高度。 今天我們要根據樹的高度由低到高進行修剪,經過修剪後的樹會變成草皮,我們要從(0, 0)出發,依序走訪所有的樹,輸出修剪所有的樹所需經過最短的距離,若有任何一棵樹無法抵達,則輸出-1
### 輸入與輸出 ### Input: [ [1,2,3], [0,0,4], [7,6,5]] Output: 6
Input: [ [1,2,3], [0,0,0], [7,6,5]] Output: -1
Input: [ [2,3,4], [0,0,5], [8,7,6]] Output: 6 Explanation: You started from the point (0,0) and you can cut off the tree in (0,0) directly without walking.
### 方法 ### 我先將所有非0或1的數加入一個陣列中,將其排序後由小至大取出,利用BFS計算從目前位置到各點的最短距離,取出目前位置到欲修剪的距離。 很不幸的我的方法吃了一發 TLE ,應該是做的 BFS 有太多多餘的範圍了,應該只要找出目前位置到目的地的最短距離就好,之後若有時間再想辦法補上新的方法吧。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Solution(object):
def cutOffTree(self, forest):
import math
self.forest = forest
self.r, self.c = len(self.forest), len(self.forest[0])
f = [col for row in forest for col in row if col != 0 and col != 1]
f.sort(reverse=True)
total_step = 0
cur_pos = (0, 0)
while f:
self.num_step = [[math.inf for j in range(self.c)] for i in range(self.r)]
self.num_step[cur_pos[0]][cur_pos[1]] = 0
self.min_step(cur_pos)
next_cut = f.pop()
next_pos = self.find_pos(next_cut)
if not self.num_step[next_pos[0]][next_pos[1]] < math.inf:
return -1
total_step += self.num_step[next_pos[0]][next_pos[1]]
cur_pos = next_pos

return total_step

def min_step(self, pos):
i, j = pos[0], pos[1]
# print(i, j, self.num_step[i][j])

if not (0 <= i < self.r and 0 <= j < self.c):
return

if 0 <= i - 1 < self.r and 0 <= j < self.c and self.forest[i - 1][j]:
if self.num_step[i - 1][j] >= self.num_step[i][j] + 1:
self.num_step[i - 1][j] = self.num_step[i][j] + 1
self.min_step((i - 1, j))

if 0 <= i + 1 < self.r and 0 <= j < self.c and self.forest[i + 1][j]:
if self.num_step[i + 1][j] >= self.num_step[i][j] + 1:
self.num_step[i + 1][j] = self.num_step[i][j] + 1
self.min_step((i + 1, j))

if 0 <= i < self.r and 0 <= j - 1 < self.c and self.forest[i][j - 1]:
if self.num_step[i][j - 1] >= self.num_step[i][j] + 1:
self.num_step[i][j - 1] = self.num_step[i][j] + 1
self.min_step((i, j - 1))

if 0 <= i < self.r and 0 <= j + 1 < self.c and self.forest[i][j + 1]:
if self.num_step[i][j + 1] >= self.num_step[i][j] + 1:
self.num_step[i][j + 1] = self.num_step[i][j] + 1
self.min_step((i, j + 1))

def find_pos(self, num):
for i in range(len(self.forest)):
if num in self.forest[i]:
return (i, self.forest[i].index(num))
return -1

第4題 673. Number of Longest Increasing Subsequence

問題

給一個未排序的整數陣列,找出最長的遞增子序列的數量。

輸入與輸出

Input: [1,3,5,4,7]
Output: 2
Explanation: The two longest increasing subsequence are [1, 3, 4, 7] and [1, 3, 5, 7].

Input: [2,2,2,2,2]
Output: 5
Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is 1, so output 5.

方法

計算LIS的長度有兩種思維方式,第一種是找出哪些數字能接在nums[i]後面,第二種是找出nums[i]能接在哪些數字後面,這裡採用第二種方法。

這裡需要用到兩個陣列: 1. LIS: LIS[i]代表以nums[i]結束的最長遞增子序列的長度 2. cnt: cnt[i]代表以nums[i]結束的最長遞增子序列的數量

假設nums[i]能接在nums[j]後面,代表nums[i] > nums[j],這裡有三種狀況可以討論: 1. LIS[i] > LIS[j] + 1 : nums[i]接在 nums[j]後面比原本還要短,不接 2. LIS[i] = LIS[j] + 1 : nums[i]接在 nums[j]後面比跟原本一樣長,只要把數量相加就好 3. LIS[i] < LIS[j] + 1 : nums[i]接在 nums[j]後面比原本還要長,長度加1,繼承前面的數量

最後將所有LIS[i]為最大值所對應的cnt[i]相加即為答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def findNumberOfLIS(self, nums):
if nums == []:
return 0

# 初始化陣列,每個數字本身就是長度為1的LIS
LIS, cnt = [1] * len(nums), [1] * len(nums)

# nums[i]能接在哪些數字後面
for i in range(1, len(nums)):
for j in range(0, i):
if nums[i] > nums[j]:
if LIS[i] == LIS[j] + 1:
cnt[i] += cnt[j]
elif LIS[i] < LIS[j] + 1:
cnt[i] = cnt[j]
LIS[i] = LIS[j] + 1
return sum((y for x, y in zip(LIS, cnt) if x == max(LIS)))