LeetCode基本记录【5】// BASIC NOTES AND CODES OF LEETCODE [ 5 ]

LeetCode基本记录【5】

78. Subsets

Given a set of distinct integers, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,3], a solution is:

[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

# 实际上可以看作是一种递归的思想,比如要生成一个集合S并集上一个数字x的新集合的子集,方法就是将S的子集们与S的子集们后面加上一个x组成的这些
# 新的子集合并起来,比如[1,2]的子集是{[],[1],[2],[1,2]},而[1,2,3]的子集就是前面这些加上{[3],[1,3],[2,3],[1,2,3]},用该规律容易得到下面代码
class Solution(object):
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        sub = [[]]
        for num in nums:
            sub += [s + [num] for s in sub]
        return sub

Given a 2D board and a word, find if the word exists in the grid.

The word can be constructed from letters of sequentially adjacent cell, where “adjacent” cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.

For example,
Given board =

[
[‘A’,’B’,’C’,’E’],
[‘S’,’F’,’C’,’S’],
[‘A’,’D’,’E’,’E’]
]

word = “ABCCED”, -> returns true,
word = “SEE”, -> returns true,
word = “ABCB”, -> returns false.

# 设计一个helper函数,可以递归地调用,从而在当前位置匹配的前提下进行下一步的查找,所谓下一步就是指在该点向四邻域移动,并且把要查找的word
# 缩短一个,为了保证访问过的不在访问,在每个点作为起始位置进行查找时,把每一步找到的位置置空,如果最后没有return True,那么最后还要把这些
# 字母放回来,进行下一个位置的遍历。具体代码如下:
class Solution(object):
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        if not board : return False
        if not word : return True
        for i in range(len(board)) :
            for j in range(len(board[0])) :
                if self.helper(board, word, i, j) :
                    return True
        return False


    def helper(self, board, word, i, j):
        if board[i][j] != word[0]:
            return False
        else:
            if not word[1:] :
                return True
            else:
                board[i][j] = ''
                if i > 0 :
                    if self.helper(board, word[1:], i-1, j) :
                        return True
                if j > 0 :
                    if self.helper(board, word[1:], i, j-1) :
                        return True
                if i < len(board) - 1 :
                    if self.helper(board, word[1:], i+1, j) :
                        return True
                if j < len(board[0]) - 1 :
                    if self.helper(board, word[1:], i, j+1) :
                        return True
                board[i][j] = word[0]
                return False

80. Remove Duplicates from Sorted Array II

Follow up for “Remove Duplicates”:
What if duplicates are allowed at most twice?

For example,
Given sorted array nums = [1,1,1,2,2,3],

Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3. It doesn’t matter what you leave beyond the new length.

# 首先维护一个查看是否为duplicate(这里特指数目大于2)的指针(记为ck)和一个操作的指针(记为op),每次比较ck指向的数值是否大于op的最后一个
# 或者大于op的倒数第二个。这里的op指向的是已经选中的list中的最末尾位置,之所以说它是操作的指针,是因为如果满足了比较的ck就要被接到op的下一个
# 位置,如果大于最后一个说明此时ck指向的是一个op之前没有的数字,故加上,如果大于倒数第二个,但是不大于倒数第一,说明ck指向的是和倒数第一
# 同样的,但是和倒数第二不同,也就说明它是重复了第二次的某个元素,如果都不满足,说明肯定是重复3次及以上了,不加入我们的结果list,这里ck指针
# 直接用了num in nums,因为不需要用它的下标。
class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        op = 0
        for num in nums:
            if op < 2 or num > nums[op - 1] or num > nums[op - 2] :
                nums[op] = num
                op += 1
        return op

81. Search in Rotated Sorted Array II

Follow up for "Search in Rotated Sorted Array":
What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Write a function to determine if a given target is in the array.

The array may contain duplicates.

# 有duplicates的话就先把两边的duplicates去掉,其他和之前的rotated array的搜索相同,当成二分搜索即可
class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: bool
        """
        if len(nums) == 1 :
            return True if nums[0] == target else False
        l, r = 0, len(nums) - 1
        while l <= r :
            mid = (l + r) // 2
            if nums[mid] == target:
                return True
            while l < mid and nums[l] == nums[mid]:
                l += 1
            while r > mid and nums[r] == nums[mid]:
                r -= 1
            if nums[mid] >= nums[l] :
                if target >= nums[l] and target < nums[mid] :
                    r = mid - 1
                else :
                    l = mid + 1
            else :
                if target > nums[mid] and target <= nums[r] :
                    l = mid + 1
                else:
                    r = mid - 1
        return False

82. Remove Duplicates from Sorted List II

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.

# 题目本身不难。。。但是一用到指针的链表就容易出错,最好给一个实例来按照算法的步骤一步步走一下,看看每种情况每个指针分别指向哪里。
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        dummy = ListNode(0)
        dummy.next = head
        pre = dummy
        cur = head
        while cur:
            if not cur.next:
                return dummy.next
            if cur.next.val != cur.val:
                pre = cur
                cur = cur.next
            else:
                while cur.next.val == cur.val:
                    cur.next = cur.next.next
                    if not cur.next:
                        pre.next = None
                        return dummy.next
                pre.next = cur.next
                cur = cur.next

86. Partition List

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.

# 思路较简单,写的虽然比较啰嗦但是逻辑还是对的,可是最后总是TLE。。。
# 看了discuss上的一个post,找到了原因:没有写 hi.next = None,缺少这句话如果原来的list不是以大数结尾的话,
# 就会造成死循环,大数指向小数,而小数又会遍历完以后再指向大数的数列。。。
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def partition(self, head, x):
        """
        :type head: ListNode
        :type x: int
        :rtype: ListNode
        """
        lo, hi, first_low, first_high = None, None, None, None
        cur = head
        while cur:
            if cur.val < x:
                if lo == None:
                    lo = cur
                    first_low = cur
                else:
                    lo.next = cur
                    lo = cur
            else:
                if hi == None:
                    hi = cur
                    first_high = cur
                else:
                    hi.next = cur
                    hi = cur
            cur = cur.next
        if not lo and not hi : return None
        elif not lo or not hi : return head
        else :
            lo.next = first_high
            hi.next = None
            return first_low

89. Gray Code

The gray code is a binary numeral system where two successive values differ in only one bit.

Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.

For example, given n = 2, return [0,1,3,2]. Its gray code sequence is:

00 - 0
01 - 1
11 - 3
10 - 2

Note:
For a given n, a gray code sequence is not uniquely defined.

For example, [0,2,3,1] is also a valid gray code sequence according to the above definition.

For now, the judge is able to judge based on one instance of gray code sequence. Sorry about that.

# 格雷码的生成方法,可以递归的生成:比如要生成n-bit 的格雷码,可以先生成n-1的,然后正序反序各写一遍,并分别给正反序的第一位加上一个0和1
# 用递归的方法,可以在python里写成one-liner
class Solution(object):
    def grayCode(self, n):
        """
        :type n: int
        :rtype: List[int]
        """
        return range(n+1) if n < 2  else self.grayCode(n-1)+[x + reduce(lambda x,y : x*y, [2]*(n-1)) for x in self.grayCode(n-1)[::-1]]

90. Subsets II

Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,2], a solution is:

[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]

# 有重复元素的subsets问题,如果要用dfs的话需要在有重复的地方预先剪枝,也可以用78题的思路来做,加上避免重复的if语句即可
# 先按照78题的思路来,考虑到如果有重复,那么这两个元素和res前面的依次合并得到的结果是完全相同的,所以考虑加入第二个的时候就不必再次和第一个
# 加入以前的所有元素做连接,因此要只对第一个元素产生出来的新的那些做连接即可。(这里的第一和第二指的是相同的元素的第一个和第二个,多个同理)

class Solution(object):
    def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = [[]]
        nums = sorted(nums)
        for i, num in enumerate(nums):
            if not i or num != nums[i-1]:
                l = len(res)
            for idx in range(len(res) - l, len(res)):
                res += [res[idx] + [num]]
        return res

# 下面是标准的dfs的解法,在这里简单总结一下backtracking的helper函数或者叫dfs函数再之前leetcode题目中的各种情况
# helper函数可以写成下面的形式:
# def helper(self, nums, target, idx, path, res)
#     if target_cannot_be_reached: return
#     if target reached:  ## update our result if there's a suitable solution path
#          res.append(path)
#          return 
#     for i in range( idx related index, len(nums)): ## this is a dfs process
#         some judgement (if needed)
#         self.helper( nums, target_new, index or sth else, path updated by attach of current item or sth else, res)
# 主要有这么几种题型:
# 1.
# 对于集合中取出几个数相加为某个定值的,target就是那个值,每调用一次,也就是树每长一层,target就要减去当前的值,并把当前的值
# 加入到path中,表示这是我们的加数序列,然后res.append 的条件就是target == 0,也就是path中的这些数的和刚好是target。那么为了对没有合适解的
# 路径有返回,那么还要加上一个直接返回(就是上面的第一个if语句),对于本问题就是target < 0 。
# 2. 
# 对于permutation类的问题,target就是dfs深度,每次减一,到零就返回并res.append,而且在dfs process里index是除了idx的所有其他的(这里说的是无
# 重复的情况,若有重复,先判断去重,判断就在每次helper调用之前,因为如果两个数一样,他们长出来的子树肯定是一样的,所以只保留一个就好,去重
# 的方法就是和前面的一个比较,如果相等,那么就跳过本次,continue,从这里我们也可以看出来,要想让相等的都相邻,首先我们要在主函数里面执行一次
# 排序操作)
# 3. 
# 对于combination的问题,比如n取k,target就是k,每次减一,等于0就返回,表示我们的树的深度达到了k,也就是有了k个元素在path中
# 如果combination有重复,那么也是需要先排序,对于重复元素的第二个(也就是值等于前面一个的那个元素),不做处理,直接continue。
# 4.
# 对于subsets问题,它没有target,因为不限定长度是多少,所以只要进来一次helper,就做一个res.append,如果有重复,比如本题,那么也是要先去重,
# 去重方法就是先排序,再判断是否为duplicates的第一个。code如下所示:

class Solution(object):
    def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        nums = sorted(nums)
        self.helper(nums, 0, [], res)
        return res

    def helper(self, nums, idx, path, res):
        res.append(path)
        for i in range(idx, len(nums)):
            if i > idx and nums[i] == nums[i-1]:
                continue
            self.helper(nums, i+1, path + [nums[i]], res)
        return res

91. Decode Ways

A message containing letters from A-Z is being encoded to numbers using the following mapping:

‘A’ -> 1
‘B’ -> 2

‘Z’ -> 26

Given an encoded message containing digits, determine the total number of ways to decode it.

For example,
Given encoded message “12”, it could be decoded as “AB” (1 2) or “L” (12).

The number of ways decoding “12” is 2.

# 利用动态规划,dynamic programming,找到最优子结构,建立矩阵,递推求解即可
class Solution(object):
    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s : return 0
        dp = [0] * len(s)
        for i in range(len(s)):
            if i == 0 : 
                if s[i] == '0' : return 0
                else : dp[i] = 1
            if i > 0 :
                if s[i] == '0' :
                    if '0' < s[i-1] < '3' :
                        dp[i] = dp[i-2] if i > 1 else 1
                    else :
                        return 0
                else :
                    dp[i] = dp[i-1]
                    if '09' < s[i-1:i+1] < '27' :
                        dp[i] = dp[i-1] + dp[i-2] if i > 1 else 2
        return dp[-1]

92. Reverse Linked List II

Reverse a linked list from position m to n. Do it in-place and in one-pass.

For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,

return 1->4->3->2->5->NULL.

Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.

# 先找到第m个的位置,然后数n-m+1个数,没看到一个就进行一次翻转,也就是把后面的next指针指向自己,第一个先指向空,最后一个由第m-1个next指向
# 然后把指向空的那个指向后面的linked list即可,注意先后顺序。
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def reverseBetween(self, head, m, n):
        """
        :type head: ListNode
        :type m: int
        :type n: int
        :rtype: ListNode
        """
        if m == n : return head
        dummy = ListNode(0)
        dummy.next = head
        cur = dummy
        for i in range(m-1):
            cur = cur.next
        pre = cur
        end = None
        cur = cur.next
        for j in range(n-m+1):
            t = cur.next
            cur.next = end
            end = cur
            cur = t
        pre.next.next = cur
        pre.next = end
        return dummy.next

又十题目完结,发现leetcode的题目是有分类的,最近总是回溯和序列和链表之类的操作。后面的若干项貌似是和树有关。。。

2018年04月04日23:25:10

posted @ 2018-04-04 23:28  毛利小九郎  阅读(99)  评论(0编辑  收藏  举报