分類總結(jié)


1、判斷鏈表循環(huán)

141、 Linked List Cycle

判斷鏈表是否是循環(huán)鏈表。思路主要有兩種,第一種是將所有的節(jié)點(diǎn)的next指向head,如果存在環(huán)則會(huì)出現(xiàn)某個(gè)節(jié)點(diǎn)的next是head,否則最后一個(gè)元素next為None,非環(huán)。

# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        node = head
        while node is not None:
            if node.next == head:
                return True
            temp = node.next
            node.next = head
            node = temp
        return False

第二種思路是使用兩個(gè)指針,一個(gè)快指針和一個(gè)慢指針,但效率并不是很高,因?yàn)椴灰欢〞?huì)在一個(gè)回合內(nèi)相遇,可能需要幾個(gè)遍歷才能相遇。

 def hasCycle1(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        slow, fast = head, head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                return True
        return False
142. Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.

由于明確要求不能修改鏈表,所以141中第一種方法就不能使用。由于第二種方法相遇節(jié)點(diǎn)并不一定是起始節(jié)點(diǎn),需要特殊分析,如下:


image.png

image.png

參考來源:http://blog.csdn.net/ebowtang/article/details/50507131

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        slow, fast = head, head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                break
        if fast is None or fast.next is None:
            return None
        fast = head
        while slow != fast:
            slow = slow.next
            fast = fast.next
        return slow

2、兩數(shù)之和、三數(shù)之和

1、two sum

找到兩數(shù)之和為target值的下標(biāo)號(hào)列表。最簡(jiǎn)單的方法就是哈希表,如下:

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        lookup = {}
        for i, item in enumerate(nums):
            if target - item in lookup:
                return [lookup[target-item], i]
            lookup[item] = i
        return [-1, -1]

two sum還有一種方法是雙指針,一頭一尾,但是需要對(duì)元素進(jìn)行排序。這樣的話如果不考慮排序時(shí)間復(fù)雜度,可以在O(n)內(nèi)解決。

15. 3Sum

找到三數(shù)之和為0的所有組合,先要對(duì)數(shù)組進(jìn)行排序,確定一個(gè)數(shù)后再利用two sum,由于數(shù)組是排序,解決two sum問題可以采用雙指針,從前和后兩個(gè)方向查找。同時(shí),這個(gè)題目需要注意去重問題,具體到實(shí)現(xiàn)上在兩個(gè)地方,如下:

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res, length = [], len(nums)
        if length < 3:
            return res
        nums = sorted(nums)
        for i in xrange(length-2):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            temp = 0 - nums[i]
            left, right = i + 1, length - 1
            while left < right:
                if nums[left] + nums[right] == temp:
                    res.append([nums[i], nums[left], nums[right]])
                    while left < right and nums[right] == nums[right-1]:
                        right -= 1
                    while left < right and nums[left] == nums[left+1]:
                        left += 1
                    right -= 1
                    left += 1
                elif nums[left] + nums[right] > temp:
                    right -= 1
                else:
                    left += 1
        return res
16、 3Sum Closest
class Solution(object):
    def threeSumClosest(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        res, length = -1, len(nums)
        if length < 3:
            return res
        nums.sort()
        res = float("inf")
        for i in xrange(length-2):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            left, right = i + 1, length - 1
            while left < right:
                temp = nums[i]+nums[left]+nums[right]
                if abs(temp - target) < abs(res - target):
                    res = temp
                if temp > target:
                    right -= 1
                elif temp < target:
                    left += 1
                else:
                    return target
        return res

找到三個(gè)數(shù)使之與指定target值最接近,思路和15題類似,先固定一個(gè)數(shù),找另外兩個(gè)數(shù),使用雙指針的方法,確定判斷指針移動(dòng)條件時(shí)需要注意。


3、house rober問題

題意要求不能連續(xù)搶相鄰兩家。

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
       if nums == []:
            return 0
        if len(nums) == 1:
            return nums[0]
        rob, notrob = nums[0], 0
        for item in nums[1:]:
            rob, notrob = notrob + item, max(notrob, rob)
        return max(rob, notrob)

加入約束條件,第一家和最后一家不能同時(shí)搶。

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) < 2:
            return sum(nums)
        # situation 1 rob first
        rob, notrob = nums[0], nums[0]
        for item in nums[2:]:
            rob, notrob = notrob + item, max(rob,notrob)
        
        # situation 2 notrob first
        rob1, notrob1 = nums[1], 0
        for item in nums[2:]:
            rob1, notrob1 = notrob1 + item, max(rob1, notrob1)
        return max(notrob,rob1,notrob1)

4 path sum問題

1)存在問題,是否有路徑和為某一個(gè)數(shù)

leetcode 112

class Solution:
    # @param root, a tree node
    # @param sum, an integer
    # @return a boolean
    def hasPathSum(self, root, sum):
        if root is None:
            return False

        if root.left is None and root.right is None and root.val == sum:
            return True

        return self.hasPathSum(root.left, sum - root.val) or \
               self.hasPathSum(root.right, sum - root.val)

需要注意的是一定是判斷到葉子節(jié)點(diǎn)(左右子樹均為None),然后利用樹的天然遞歸性求解。

2)求解所有方案問題

leetcode 113

class Solution(object):
    def pathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: List[List[int]]
        """
        if not root: return []
        if root.left is None and root.right is None:
            if sum == root.val:
                return [[root.val]]
            else:
                return []
        a = self.pathSum(root.left, sum - root.val) + \
            self.pathSum(root.right, sum - root.val)
        return [[root.val] + i for i in a]

上面的方法比較巧妙,但也比較難想得到。這種類型的問題首先想到的是遍歷,類似回溯求解合適解,

class Solution:
    # 返回二維列表,內(nèi)部每個(gè)列表表示找到的路徑
    def FindPath(self, root, expectNumber):
        # write code here
        if root is None:
            return []
        self.res = []
        self.helper(root, [], expectNumber)
        return self.res

    def helper(self, root, subres, number):
        if number == root.val and root.left is None and root.right is None:
            subres.append(root.val)
            self.res.append(subres[:])
            subres.pop()
            return
        if number < 0:
            return
        if root.left:
            subres.append(root.val)
            self.helper(root.left, subres, number-root.val)
            subres.pop()
        if root.right:
            subres.append(root.val)
            self.helper(root.right, subres, number - root.val)
            subres.pop()

其實(shí),leetcode 112是DFS的具體應(yīng)用,遍歷每一種情況,而leetcode 113中下面解法是回溯。

5、全排列問題

leetcode中46題,可以比較方便使用回溯,但有個(gè)前提,就是所有的數(shù)字都是不相同的。

class Solution(object):
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        self.result = []
        sub = []
        self.dfs(nums,sub)
        return self.result

    def dfs(self, nums, sub):
        if len(sub) == len(nums):
            print sub
            self.result.append(sub[:])
        for m in nums:
            if m in sub:
                continue
            sub.append(m)
            self.dfs(nums, sub)
            sub.remove(m)

上面的方法比較直接,但是效率不高,有一種通用的方法:

class Solution:
    def Permutation(self, ss):
        # write code here
        self.res = []
        self.helper(list(ss), 0, len(ss))
        return self.res

    def helper(self, s, start, end):
        if start > end:
            return
        if start == end:
            self.res.append(s[:])
        else:
            for i in range(start, end):
                s[start], s[i] = s[i], s[start]
                self.helper(s, start + 1, end)
                s[start], s[i] = s[i], s[start]  # 也是回溯的思想
s = Solution()
print s.Permutation('abc')

輸出為:

[['a', 'b', 'c'], ['a', 'c', 'b'], ['b', 'a', 'c'], ['b', 'c', 'a'], ['c', 'b', 'a'], ['c', 'a', 'b']]

理論基礎(chǔ):


image.png

而在劍指offer中的26題,情況不一樣,要無(wú)重復(fù),并且輸入是字符串,如果用交換方法的化在python中不行,因?yàn)閜ython中不能給字符串賦值。

# -*- coding:utf-8 -*-
class Solution:
    def Permutation(self, ss):
        # write code here
        if ss == '':
            return []
        self.res = set()
        self.helper(list(ss), 0, len(ss))
        return sorted(self.res)

    def helper(self, s, start, end):
        if start > end:
            return
        if start == end:
            self.res.add(''.join(s))
        else:
            for i in range(start, end):
                s[start], s[i] = s[i], s[start]
                self.helper(s, start + 1, end)
                s[start], s[i] = s[i], s[start]



import itertools
class Solution2:
    def Permutation(self, ss):
        # write code here
        result = []
        if not ss:
            return []
        else:
            res = itertools.permutations(ss)
            for i in res:
                if "".join(i) not in result:
                    result.append("".join(i))
        return result

6、組合問題

7、動(dòng)態(tài)規(guī)劃路徑問題

給定一個(gè) m x n 矩陣,求出左上節(jié)點(diǎn)到右下節(jié)點(diǎn)的一條最小路徑。
這樣的題目看起來是要找到一條路徑,但還是需要將所有的中間節(jié)點(diǎn)的值都求出來。

class Solution(object):
    def minPathSum(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        m, n = len(grid), len(grid[0])
        res = [[0 for _ in xrange(n)] for _ in xrange(m)]
        res[0][0] = grid[0][0]
        for i in xrange(1, m):
            res[i][0] = res[i-1][0] + grid[i][0]
        for j in xrange(1, n):
            res[0][j] = res[0][j-1] + grid[0][j]
        for i in xrange(1, m):
            for j in xrange(1, n):
                res[i][j] = min(res[i-1][j], res[i][j-1]) + grid[i][j]

        return res[m-1][n-1]

    def minpathsum2(self,grid):
        '''

        '''
        res = grid[0]
        m, n = len(grid), len(grid[0])
        for j in xrange(1, n):
            res[j] = res[j-1] + grid[0][j]
        for i in xrange(1, m):
            res[0] = res[0] + grid[i][0]
            for j in xrange(1, n):
                res[j] = min(res[j], res[j-1]) + grid[i][j]

        return res[-1]

第一種方法是簡(jiǎn)單直接的,使用一個(gè)二維數(shù)組保存中間結(jié)果,如果原數(shù)組可以直接修改的話可以不用創(chuàng)建一個(gè)新的數(shù)組。第二種方法只用了一個(gè)一維數(shù)組,不難理解。
一維數(shù)組優(yōu)化方法詳細(xì)參考 https://blog.csdn.net/happyaaaaaaaaaaa/article/details/50856112

8、排序鏈表刪除問題

# -*- coding:utf-8 -*-
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
# 重復(fù)的節(jié)點(diǎn)不保存
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        if pHead is None or pHead.next is None:
            return pHead
        head = pHead
        while pHead and pHead.next:
            if pHead.val != pHead.next.val:
                pHead = pHead.next
            else:
                pHead.next = pHead.next.next
        return head

# 刪除重復(fù)節(jié)點(diǎn),包括本身節(jié)點(diǎn)
class Solution1:
    def deleteDuplication(self, pHead):
        # write code here
        if pHead is None or pHead.next is None:
            return pHead
        dummy = ListNode(-1)
        dummy.next = pHead
        pre, head = dummy, dummy
        while pHead and pHead.next:
            if pHead.val != pHead.next.val:
                pHead = pHead.next
                pre = pre.next
            else:
                while pHead and pHead.next and pHead.val == pHead.next.val:
                    pHead = pHead.next
                pHead = pHead.next
                pre.next = pHead
        return dummy.next

上面為兩種場(chǎng)景,第一是保存一個(gè)重復(fù)節(jié)點(diǎn),第二是不保存。需要注意的是一些細(xì)節(jié)。
Java版

public class DeleteNodeInLinklist {
    public static ListNode DeleteDupNode(ListNode node){
        if(node==null || node.next==null)
            return node;
        ListNode dummy = new ListNode(-1);
        dummy.next = node;
        ListNode ptr = dummy;
        while(node != null && node.next != null){
            if(node.val != node.next.val){
                node = node.next;
                ptr = ptr.next;
            }else {
                while((node != null) && (node.next != null) && (node.val==node.next.val)){
                    node = node.next;
                }
                node = node.next;
                ptr.next = node;
            }
        }
        return dummy.next;
    }
    // 刪除重復(fù)節(jié)點(diǎn)但保留一個(gè)
    public static ListNode DeleteDupNodeWithOne(ListNode node){
        if(node==null || node.next==null)
            return node;
        ListNode current = node;
        while(current != null && current.next != null){
            if(current.val == current.next.val)
                current.next = current.next.next;
            else
                current = current.next;
        }
        return node;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容