美文网首页
分类总结

分类总结

作者: lifesmily | 来源:发表于2018-08-23 22:41 被阅读15次

    1、判断链表循环

    141、 Linked List Cycle

    判断链表是否是循环链表。思路主要有两种,第一种是将所有的节点的next指向head,如果存在环则会出现某个节点的next是head,否则最后一个元素next为None,非环。

    # 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
    

    第二种思路是使用两个指针,一个快指针和一个慢指针,但效率并不是很高,因为不一定会在一个回合内相遇,可能需要几个遍历才能相遇。

     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中第一种方法就不能使用。由于第二种方法相遇节点并不一定是起始节点,需要特殊分析,如下:


    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、两数之和、三数之和

    1、two sum

    找到两数之和为target值的下标号列表。最简单的方法就是哈希表,如下:

    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还有一种方法是双指针,一头一尾,但是需要对元素进行排序。这样的话如果不考虑排序时间复杂度,可以在O(n)内解决。

    15. 3Sum

    找到三数之和为0的所有组合,先要对数组进行排序,确定一个数后再利用two sum,由于数组是排序,解决two sum问题可以采用双指针,从前和后两个方向查找。同时,这个题目需要注意去重问题,具体到实现上在两个地方,如下:

    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
    

    找到三个数使之与指定target值最接近,思路和15题类似,先固定一个数,找另外两个数,使用双指针的方法,确定判断指针移动条件时需要注意。


    3、house rober问题

    题意要求不能连续抢相邻两家。

    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)
    

    加入约束条件,第一家和最后一家不能同时抢。

    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)存在问题,是否有路径和为某一个数

    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)
    

    需要注意的是一定是判断到叶子节点(左右子树均为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:
        # 返回二维列表,内部每个列表表示找到的路径
        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()
    

    其实,leetcode 112是DFS的具体应用,遍历每一种情况,而leetcode 113中下面解法是回溯。

    5、全排列问题

    leetcode中46题,可以比较方便使用回溯,但有个前提,就是所有的数字都是不相同的。

    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']]
    

    理论基础:


    image.png

    而在剑指offer中的26题,情况不一样,要无重复,并且输入是字符串,如果用交换方法的化在python中不行,因为python中不能给字符串赋值。

    # -*- 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、动态规划路径问题

    给定一个 m x 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]
    

    第一种方法是简单直接的,使用一个二维数组保存中间结果,如果原数组可以直接修改的话可以不用创建一个新的数组。第二种方法只用了一个一维数组,不难理解。
    一维数组优化方法详细参考 https://blog.csdn.net/happyaaaaaaaaaaa/article/details/50856112

    8、排序链表删除问题

    # -*- coding:utf-8 -*-
    class ListNode:
        def __init__(self, x):
            self.val = x
            self.next = None
    # 重复的节点不保存
    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
    
    # 删除重复节点,包括本身节点
    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
    

    上面为两种场景,第一是保存一个重复节点,第二是不保存。需要注意的是一些细节。
    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;
        }
        // 删除重复节点但保留一个
        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;
        }
    }
    

    相关文章

      网友评论

          本文标题:分类总结

          本文链接:https://www.haomeiwen.com/subject/xyqtfftx.html