算法相关知识点

 

 

 

 

 

 

Classical Question

c1.Quick Sort / Top K problem

class Solution:
    """
    @param n: An integer
    @param nums: An array
    @return: the Kth largest element
    """
    def kthLargestElement(self, n, nums):
        # write your code here
        length = len(nums)
        if n>length or n==0:
            return None
        half_quicksort(nums,0,length-1)
        return nums[-n]
        
def half_quicksort(nums,start,end):
    if start<end:
        left,right=start,end
        pivot = nums[start]
        while left<right:
            while left<right and nums[right]>=pivot:
                right-=1
            nums[left],nums[right]=nums[right],nums[left]
            while left<right and nums[left]<pivot:
                left+=1
            nums[left],nums[right]=nums[right],nums[left]
        half_quicksort(nums,right+1,end)
        half_quicksort(nums,start,right-1)
快排
class Solution:
    """
    @param n: An integer
    @param nums: An array
    @return: the Kth largest element
    """
    
    #方法二,利用二叉堆
    def kthLargestElement2(self, n, nums):
        import heapq
        length = len(nums)
        if n>length or n==0:
            return None
        return heapq.nlargest(n,nums)[n-1]
堆排序
思路:
    快速选择算法 的平均时间复杂度为 O(N){O}(N)O(N)。就像快速排序那样,本算法也是 Tony Hoare 发明的,因此也被称为 Hoare选择算法。
"""
本方法大致上与快速排序相同。简便起见,注意到第 k 个最大元素也就是第 N - k 个最小元素,因此可以用第 k 小算法来解决本问题。

首先,我们选择一个枢轴,并在线性时间内定义其在排序数组中的位置。这可以通过 划分算法 的帮助来完成。

    为了实现划分,沿着数组移动,将每个元素与枢轴进行比较,并将小于枢轴的所有元素移动到枢轴的左侧。

这样,在输出的数组中,枢轴达到其合适位置。所有小于枢轴的元素都在其左侧,所有大于或等于的元素都在其右侧。

这样,数组就被分成了两部分。如果是快速排序算法,会在这里递归地对两部分进行快速排序,时间复杂度为 O(Nlog⁡N)。

而在这里,由于知道要找的第 N - k 小的元素在哪部分中,我们不需要对两部分都做处理,这样就将平均时间复杂度下降到 O(N)。

"""

class Solution:
    """
    @param n: An integer
    @param nums: An array
    @return: the Kth largest element
    """
    def kthLargestElement(self, n, nums):
        # write your code here
        length = len(nums)
        if n>length or n==0:
            return None
        return half_quicksort(nums,n,0,length-1)
        
        
def half_quicksort(nums,k,start,end):
    if k==1 and start==end:
        return nums[start]
    if start<end:
        left,right=start,end
        pivot = nums[start]
        while left<right:
            while left<right and nums[right]>=pivot:
                right-=1
            nums[left],nums[right]=nums[right],nums[left]
            while left<right and nums[left]<pivot:
                left+=1
            nums[left],nums[right]=nums[right],nums[left]
        
        if end-right>k-1:
            return half_quicksort(nums,k,right+1,end)
        elif end-right<k-1:
            return half_quicksort(nums,k-(end-right+1),start,right-1)
        else:
            return nums[right]
Hoare选择算法

 

c2.Binary Search

 

 Closest K Elements:

https://www.lintcode.com/problem/k-closest-points/description

class Solution:
    """
    @param A: an integer array
    @param target: An integer
    @param k: An integer
    @return: an integer array
    """
    def kClosestNumbers(self, A, target, k):
        # write your code here
        sub=100000
        nearest=-1
        start = 0
        end = len(A)-1
        while start<=end:
            mid = (start+end)//2
            temp = abs(A[mid]-target)
            if temp<sub:
                sub = temp
                nearest = mid
            if A[mid]>target:
                end = mid-1
            elif A[mid]<target:
                start = mid+1
            elif A[mid]==target:
                break
        out=[]
        if nearest!=-1 and k>0:
            out.append(A[nearest])
            i=1
            left,right=nearest-1,nearest+1
            while left>=0 and right<=len(A)-1 and i<k:
                if abs(A[left]-target)<=abs(A[right]-target):
                    out.append(A[left])
                    left = left-1
                else:
                    out.append(A[right])
                    right = right+1
                i = i+1
                
            if i<k and left<0:
                out.extend(A[right:right+k-i])
            if i<k and right>len(A)-1:
                out.extend(A[left:left-(k-i):-1])
        return out
if __name__=="__main__":
    s = Solution()
    print(s.kClosestNumbers( A = [1, 2, 3], target = 2, k = 3))
    print(s.kClosestNumbers(A = [1, 4, 6, 8], target = 3, k = 3))
    print(s.kClosestNumbers(A = [1,4,6,10,20], target = 21, k = 4))
    print(s.kClosestNumbers(A = [1,2,4,5,6,7,8,10], target = 5, k = 0))
    print(s.kClosestNumbers(A = [1,4,8,12,16,28,38], target = 12, k = 4))
    print(s.kClosestNumbers(A = [1,4,6,8], target = 3, k = 3))
            
最近的K个元素

https://www.lintcode.com/problem/k-closest-points/description

"""
Definition for a point.
class Point:
    def __init__(self, a=0, b=0):
        self.x = a
        self.y = b
"""

class Solution:
    """
    @param points: a list of points
    @param origin: a point
    @param k: An integer
    @return: the k closest points
    """
    def kClosest(self, points, origin, k):
        # write your code here
        import heapq
        ret = []
        if len(points)==0 or k<0 or  k>len(points):
            return ret
        hp = []
        for point in points:
            dis = (point.x-origin.x)*(point.x-origin.x) + (point.y-origin.y)*(point.y-origin.y)
            heapq.heappush(hp, [dis, point.x, point.y])
        
        for i in range(k):
            _, x, y = heapq.heappop(hp)
            ret.append([x, y])
        return ret
最近的k个点

 

C3. Binary Tree Traversal

 

 Zigzag order

https://www.lintcode.com/problem/binary-tree-zigzag-level-order-traversal/description

class Solution:
    """
    @param root: A Tree
    @return: A list of lists of integer include the zigzag level order traversal of its nodes' values.
    """
    def zigzagLevelOrder(self, root):
        # write your code here
        ret = []
        if not root or not root.val:
            return ret
        q = [[root]]
        i = 0
        while q:
            temp = []
            val = []
            cur = q.pop(0)
            for node in cur:
                val.append(node.val)
                if node.left:
                    temp.append(node.left)
                if node.right:
                    temp.append(node.right)
            if i&1:
                val = val[::-1]
            if temp:
                q.append(temp)
            ret.append(val)
            i += 1
        return ret
View Code

right-view

https://www.lintcode.com/problem/binary-tree-right-side-view/description

"""
Definition of TreeNode:
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: the root of the given tree
    @return: the values of the nodes you can see ordered from top to bottom
    """
    def rightSideView(self, root):
        # write your code here
        ret = []
        if not root or not root.val:
            return ret
        q = [[root]]
        while q:
            temp = []
            cur = q.pop(0)
            for node in cur:
                if node.left:
                    temp.append(node.left)
                if node.right:
                    temp.append(node.right)
            ret.append(node.val)
            if temp:
                q.append(temp)
        return ret
                    
View Code

Balanced search tree validation

https://www.lintcode.com/problem/balanced-binary-tree/description

"""
Definition of TreeNode:
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: The root of binary tree.
    @return: True if this Binary tree is Balanced, or false.
    """
    def isBalanced(self, root):
        # write your code here
        
        balanced, _ = self.cal_balance(root)
        return balanced
        
    def cal_balance(self, node):
        if node==None:
            return True, 0
        balanced, leftHeight = self.cal_balance(node.left)
        if not balanced:
            return False, 0
        balanced, rightHeight = self.cal_balance(node.right)
        if not balanced:
            return False, 0
        diff = abs(leftHeight-rightHeight)
        return diff<=1, max(leftHeight, rightHeight)+1
View Code

Binary search tree validation

https://www.lintcode.com/problem/validate-binary-search-tree/description

#coding:utf-8
"""
95. Validate Binary Search Tree
Description

    Given a binary tree, determine if it is a valid binary search tree (BST).

    Assume a BST is defined as follows:

        The left subtree of a node contains only nodes with keys less than the node's key.
        The right subtree of a node contains only nodes with keys greater than the node's key.
        Both the left and right subtrees must also be binary search trees.
        A single node tree is a BST

Example 1:

    Input:  {-1}
    Output:true
    Explanation:
    For the following binary tree(only one node):
              -1
    This is a binary search tree.

Example 2:

    Input:  {2,1,4,#,#,3,5}
    Output: true
    For the following binary tree:
          2
         / \
        1   4
           / \
          3   5
    This is a binary search tree.


"""
#中序遍历,挨个比较大小

"""
Definition of TreeNode:
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: The root of binary tree.
    @return: True if the binary tree is BST, or false
    """
    def isValidBST(self, root):
        # write your code here
        if root==None:
            return True
        self.valid=True
        self.lastVal=None
        self.helper(root)
        return self.valid
    
    def helper(self,node):
        if node==None:
            return 
        self.helper(node.left)
        if self.lastVal!=None and self.lastVal>=node.val:
            self.valid=False
            return 
        self.lastVal=node.val
        self.helper(node.right)
View Code

 

C4.Linked List

https://www.cnblogs.com/silence-cho/p/10041616.html 

Reverse Linked list

https://www.lintcode.com/problem/reverse-linked-list-ii/description

class Solution:
    """
    @param head: ListNode head is the head of the linked list 
    @param m: An integer
    @param n: An integer
    @return: The head of the reversed ListNode
    """
    def reverseBetween(self, head, m, n):
        # write your code here
        if not head or m<1 or n<1 or m>=n:
            return head
        
        start = head
        pre_start = start
        while m != 1 and start:
            pre_start = start
            start = start.next
            m -= 1
            n -= 1
        if m>1:
            return head
        pre = start
        cur = pre.next
        n -= 1
        while n !=1 and cur:
            temp = cur.next
            cur.next = pre
            pre = cur
            cur = temp
            n -= 1
        if n>1:
            return head
        start.next = cur.next
        cur.next = pre
        if start!=head:
            pre_start.next = cur
        else:
            head = cur
        return head
View Code

https://www.lintcode.com/problem/reverse-linked-list/description

#coding:utf-8

"""
35. Reverse Linked List

Reverse a linked list.
Example

Example 1:

Input: 1->2->3->null
Output: 3->2->1->null

Example 2:

Input: 1->2->3->4->null
Output: 4->3->2->1->null

Challenge

Reverse it in-place and in one-pass

"""

"""
Definition of ListNode

class ListNode(object):

    def __init__(self, val, next=None):
        self.val = val
        self.next = next
"""

class Solution:
    """
    @param head: n
    @return: The new head of reversed linked list.
    """
    def reverse(self, head):
        # write your code here
        if not head:
            return head
        pre = head
        cur = head.next
        while cur:
            temp = cur.next
            cur.next = pre
            pre = cur
            cur = temp
        head.next = cur
        return pre
        
#递归法
class Solution:
    """
    @param head: n
    @return: The new head of reversed linked list.
    """
    def reverse(self, head):
        # write your code here
        if not head or not head.next:
            return head
        else:
            newhead = self.reverse(head.next)
            head.next.next = head
            head.next = None
            
            return newhead
View Code

Merge two linked list

https://www.lintcode.com/problem/merge-two-sorted-lists/description

#coding:utf-8

"""
165. Merge Two Sorted Lists

Merge two sorted (ascending) linked lists and return it as a new sorted list. The new sorted list should be made by splicing together the nodes of the two lists and sorted in ascending order.
Example

Example 1:
    Input: list1 = null, list2 = 0->3->3->null
    Output: 0->3->3->null


Example 2:
    Input:  list1 =  1->3->8->11->15->null, list2 = 2->null
    Output: 1->2->3->8->11->15->null
"""

"""
Definition of ListNode
class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
"""

class Solution:
    """
    @param l1: ListNode l1 is the head of the linked list
    @param l2: ListNode l2 is the head of the linked list
    @return: ListNode head of linked list
    """
    def mergeTwoLists(self, l1, l2):
        # write your code here
        if not l1:
            return l2
        if not l2:
            return l1
        if not l1 and not l2:
            return None
        if l1.val<=l2.val:
            head = l1
            l1 = l1.next
        else:
            head = l2
            l2 = l2.next
        temp = head
        while l1 and l2:
            if l1.val <= l2.val:
                temp.next = l1
                l1 = l1.next
            else:
                temp.next = l2
                l2 = l2.next
            temp = temp.next
        if l1:
            temp.next = l1
        if l2:
            temp.next = l2
        return head
View Code

 

C5. Sqrt / Pow

Binary Search / Newton

https://www.lintcode.com/problem/sqrtx/description

#coding:utf-8

"""
141. Sqrt(x)
Implement int sqrt(int x).

Compute and return the square root of x.
Example

Example 1:
    Input:  0
    Output: 0


Example 2:
    Input:  3
    Output: 1
    
    Explanation:
    return the largest integer y that y*y <= x. 
    
Example 3:
    Input:  4
    Output: 2
    

Challenge

O(log(x))

"""
#参考:https://www.jiuzhang.com/solutions/sqrtx/

class Solution:
    """
    @param x: An integer
    @return: The sqrt of x
    """
    def sqrt(self, x):
        # write your code here
        if x==0 or x==1:
            return x
        low, high = 1, x
        while low+1<high:
            mid = (low+high)//2  #防止溢出
            if (x//mid>mid):
                low = mid
            elif (x//mid < mid):
                high = mid
            else:
                return mid
            
        if x//high < high:
            return low
        return high
        
#牛顿法
"""
牛顿迭代法。令t = sqrt(x), 根据 x = sqrt(x) * sqrt(x)构造不动点
n = t * t
n + t * t = 2 * t * t
(n / t) + t = 2 * t
t = (n / t + t) / 2
"""
class Solution:
    """
    @param x: An integer
    @return: The sqrt of x
    """
    def sqrt(self, x):
        # write your code here
        if x==0 or x==1:
            return x
        guess = 1
        while (abs(x/guess - guess)>0.1):
            guess = (x/guess +guess)/2
        return int(guess)
            
            
View Code

Recursive / Bit Operation

https://www.lintcode.com/problem/power-of-two/description

#coding:utf-8


"""
1314. Power of Two

Given an integer, write a function to determine if it is a power of two.
Example

Example

Input: n = 3
Output: false


"""
#2的幂次方,比特位数中只有一位是1,其他全是0。(也可以遍历判断是不是只有一位是1)
#比特操作
class Solution:
    """
    @param n: an integer
    @return: if n is a power of two
    """
    def isPowerOfTwo(self, n):
        # Write your code here
        if n<=0:
            return False
        flag = n&(n-1)
        return flag==0


#        
class Solution:
    """
    @param n: an integer
    @return: if n is a power of two
    """
    def isPowerOfTwo(self, n):
        # Write your code here
        if n<=0:
            return False
        while n>1:
            n = n/2
            if int(n)!=n:
                return False
        return True

#递归        
class Solution:
    """
    @param n: an integer
    @return: if n is a power of two
    """
    def isPowerOfTwo(self, n):
        # Write your code here
        if n<=0:
            return False
        # if int(n) != n:
            # return False
        if n==1:
            return True
        return self.isPowerOfTwo(n/2)
            
View Code

 

C6.Points minimum distance in a matrix

 

 Binary maze (迷宫问题)

给定一个迷宫,指明起点和终点,找出从起点出发到终点的有效可行路径,就是迷宫问题(maze problem)。

迷宫可以以二维数组来存储表示。0表示通路,1表示障碍。注意这里规定移动可以从上、下、左、右四方方向移动。坐标以行和列表示,均从0开始,给定起点(0,0)和终点(4,4),迷宫表示如下:

  • maze[5][5]={
  • {0,0,0,0,0},
  • {0,1,0,1,0},
  • {0,1,1,0,0},
  • {0,1,1,0,1},
  • {0,0,0,0,0}
  • };

那么下面的迷宫就有两条可行的路径,分别为: 
(1)(0,0) (0,1) (0,2) (0,3) (0,4) (1,4) (2,4) (2,3) (3,3) (4,3) (4,4); 
(2)(0,0) (1,0) (2,0) (3,0) (4,0) (4,1) (4,2) (4,3) (4,4) ;

可见,迷宫可行路径有可能是多条,且路径长度可能不一。

#coding:utf-8

#binary maze (迷宫问题)
"""
给定一个迷宫,指明起点和终点,找出从起点出发到终点的有效可行路径,就是迷宫问题(maze problem)。

迷宫可以以二维数组来存储表示。0表示通路,1表示障碍。注意这里规定移动可以从上、下、左、右四方方向移动。坐标以行和列表示,均从0开始,给定起点(0,0)和终点(4,4),迷宫表示如下:
[
[ 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 ],
[ 1, 0, 1, 0, 1, 1, 1, 0, 1, 1 ],
[ 1, 1, 1, 0, 1, 1, 0, 1, 0, 1 ],
[ 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
[ 1, 1, 1, 0, 1, 1, 1, 0, 1, 0 ],
[ 1, 0, 1, 1, 1, 1, 0, 1, 0, 0 ],
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 ],
[ 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 ],
[ 1, 1, 0, 0, 0, 0, 1, 0, 0, 1 ]
]
"""


def find_shortest_path(maze, start, destination):
    if len(maze)==0 or len(maze[0])==0:
        return None
    row, col = len(maze), len(maze[0])
    if start[0]<0 or start[0]>=row or start[1]<0 or start[1]>=col or destination[0]<0 or destination[0]>=row or destination[1]<0 or destination[1]>=col:
        return None
    
    visited = [[-1]*col for i in range(row)]  #存储路径长度
    pre = [[0]*col for i in range(row)]        #存储前节点
    q = [start]
    visited[start[0]][start[1]] += 1 
    path = []
    direction = [[-1, 0], [0, 1], [0, -1], [1, 0]]    
            
    while q:
        cur = q.pop(0)
        if cur==destination:
            path_length = visited[cur[0]][cur[1]]
            path.append(destination)
            temp = pre[destination[0]][destination[1]]
            while temp!=start:
                path.append(temp)
                temp = pre[temp[0]][temp[1]]
            path.append(start)
            path.reverse()
            return path_length, path
        for i in direction:
            next = [cur[0]+i[0], cur[1]+i[1]]
            if next[0]<0 or next[0]>=row or next[1]<0 or next[1]>=col or visited[next[0]][next[1]]!=-1 or maze[next[0]][next[1]]==1: #越界, 有障碍或已访问,舍去
                continue
            else:
                visited[next[0]][next[1]] = visited[cur[0]][cur[1]] + 1
                pre[next[0]][next[1]] = cur
                q.append(next)
    return None

if __name__ == "__main__":
    maze = [
        [ 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 ],
        [ 1, 0, 1, 0, 1, 1, 1, 0, 1, 1 ],
        [ 1, 1, 1, 0, 1, 1, 0, 1, 0, 1 ],
        [ 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
        [ 1, 1, 1, 0, 1, 1, 1, 0, 1, 0 ],
        [ 1, 0, 1, 1, 1, 1, 0, 1, 0, 0 ],
        [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 ],
        [ 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 ],
        [ 1, 1, 0, 0, 0, 0, 1, 0, 0, 1 ]
        ]
    # start, end = [1, 1], [1, 3]
    start, end = [4, 9], [7, 1]
    ret = find_shortest_path(maze, start, end)
    if ret:
        print(ret)
            
        
        
        
Binary maze

 

Normal maze

给定一个迷宫,指明起点和终点,找出从起点出发到终点的有效可行路径,就是迷宫问题(maze problem)。
迷宫可以以二维数组来存储表示。
坐标以行和列表示,均从0开始,如起点(0,0)和终点(4,4)
移动可以从上、下、左、右四方方向移动,数字表示上下左右邻节点到该点的距离,迷宫表示如下:
(Normal maze和Binary maze唯一的区别在于,矩阵中的数字表示邻节点到该节点的距离)
[
[ 1, 1, 1, 1],
[ 2, 3, 3, 4],
]

#coding:utf-8

#Normal maze (迷宫问题)
"""
给定一个迷宫,指明起点和终点,找出从起点出发到终点的有效可行路径,就是迷宫问题(maze problem)。
迷宫可以以二维数组来存储表示。
坐标以行和列表示,均从0开始,如起点(0,0)和终点(4,4)
移动可以从上、下、左、右四方方向移动,数字表示上下左右邻节点到该点的距离,迷宫表示如下:
(Normal maze和Binary maze唯一的区别在于,矩阵中的数字表示邻节点到该节点的距离)
[
[ 1, 1, 1, 1],
[ 2, 3, 3, 4],
]
"""

#normal maze

import heapq

def find_shortest_path(maze, start, end):
    if len(maze)==0 or len(maze[0])==0:
        return None
    row, col = len(maze), len(maze[0])
    if start[0]<0 or start[0]>=row or start[1]<0 or start[1]>=col or end[0]<0 or end[0]>=row or end[1]<0 or end[1]>=col:
        return None
    visited = [[0]*col for i in range(row)]  #存储是否访问
    pre = [[0]*col for i in range(row)]     #存储前节点
    direction = [[-1, 0], [0, 1], [0, -1], [1, 0]]
    path = []
    q = []
    heapq.heappush(q, [0, start])   #存储所有节点到起点的距离
    visited[start[0]][start[1]] = 1
    while q:
        cur = heapq.heappop(q)
        if cur[1] == end:
            shortest_distance = cur[0]
            path.append(end)
            temp = pre[end[0]][end[1]]
            while temp!= start:
                path.append(temp)
                temp = pre[temp[0]][temp[1]]
            path.append(temp)    
            path.reverse()
            return shortest_distance, path
        
        for i in direction:
            next = [cur[1][0]+i[0], cur[1][1]+i[1]]
            if 0<=next[0]<row and 0<=next[1]<col and visited[next[0]][next[1]] == 0:
                visited[next[0]][next[1]] = 1
                pre[next[0]][next[1]] = cur[1]
                dis = cur[0] + maze[next[0]][next[1]]
                heapq.heappush(q, [dis, next])
                
    return None

if __name__ == "__main__":
    maze = [
        [ 1, 1, 1, 1],
        [ 2, 3, 3, 4],
        ]
    # start, end = [1, 0], [1, 3]
    start, end = [0, 3], [1, 0]
    ret = find_shortest_path(maze, start, end)
    if ret:
        print(ret)
        
    
normal maze

C7. Number Island I&II

 

 https://www.lintcode.com/problem/number-of-islands/description

#coding:utf-8


"""
433. Number of Islands

    Given a boolean 2D matrix, 0 is represented as the sea, 1 is represented as the island. If two 1 is adjacent, we consider them in the same island. We only consider up/down/left/right adjacent.

    Find the number of islands.
    Example

Example 1:
    Input:
    [
      [1,1,0,0,0],
      [0,1,0,0,1],
      [0,0,0,1,1],
      [0,0,0,0,0],
      [0,0,0,0,1]
    ]
    Output:3

Example 2:

    Input:
    [
      [1,1]
    ]
    Output:1
"""
"""
思路:线性扫描整个二维网格,如果一个结点包含 1,则以其为根结点启动深度优先搜索。在深度优先搜索过程中,每个访问过的结点被标记为 0。计数启动深度优先搜索的根结点的数量,即为岛屿的数量。
"""
class Solution:
    """
    @param grid: a boolean 2D matrix
    @return: an integer
    """
    def numIslands(self, grid):
        # write your code here
        rows = len(grid)
        nums = 0
        if rows==0:
            return nums
        for r in range(rows):
            cols = len(grid[r])
            if cols>0:
                for c in range(cols):
                    if grid[r][c]==1:
                        dfs(grid,r,c)
                        nums+=1
        return nums

def dfs(grid,r,c):
    rows = len(grid)
    if r<0 or r>rows-1:
        return
        
    cols = len(grid[r])
    if c<0 or c>cols-1:
        return
    if grid[r][c]==0:
        return
    grid[r][c]=0   #grid[r][c]=1,将其由1设置为0,表示已经遍历
    dfs(grid,r-1,c)
    dfs(grid,r+1,c)
    dfs(grid,r,c-1)
    dfs(grid,r,c+1)
    
    
# class Solution:
    # """
    # @param grid: a boolean 2D matrix
    # @return: an integer
    # """
    # def numIslands(self, grid):
        # # write your code here
        # if len(grid)==0 or len(grid[0])==0:
            # return 0
        # row, col = len(grid), len(grid[0])
        # count = 0
        # for i in range(row):
            # for j in range(col):
                # if grid[i][j]==1:
                    # count+=1 
                    # self.dfs(grid, i, j, row, col)
        # return count
    
    # def dfs(self, grid, i, j, row, col):
        # direction = [[-1, 0], [1, 0], [0, -1], [0, 1]]
        # q = [[i, j]]
        # grid[i][j] = 0
        # while q:
            # cur = q.pop()
            # for item in direction:
                # x = cur[0] + item[0]
                # y = cur[1] + item[1]
                # if 0<=x<row and 0<=y<col and grid[x][y]==1:
                    # q.append([x, y])
                    # grid[x][y] = 0
if __name__=="__main__":
    s = Solution()
    g1 =[
      [1,1,0,0,0],
      [0,1,0,0,1],
      [0,0,0,1,1],
      [0,0,0,0,0],
      [0,0,0,0,1]
    ]
    g2=[
      [1,1]
    ]
    print(s.numIslands(g1))
    print(s.numIslands(g2))
    
Number of islands I
#coding:utf-8

"""
434. Number of Islands II

Given a n,m which means the row and column of the 2D matrix and an array of pair A( size k). Originally, the 2D matrix is all 0 which means there is only sea in the matrix. The list pair has k operator and each operator has two integer A[i].x, A[i].y means that you can change the grid matrix[A[i].x][A[i].y] from sea to island. Return how many island are there in the matrix after each operator.
Example

Example 1:

Input: n = 4, m = 5, A = [[1,1],[0,1],[3,3],[3,4]]
Output: [1,1,2,2]
Explanation:
0.  00000
    00000
    00000
    00000
1.  00000
    01000
    00000
    00000
2.  01000
    01000
    00000
    00000
3.  01000
    01000
    00000
    00010
4.  01000
    01000
    00000
    00011

Example 2:

Input: n = 3, m = 3, A = [[0,0],[0,1],[2,2],[2,1]]
Output: [1,1,2,2]

Notice

0 is represented as the sea, 1 is represented as the island. If two 1 is adjacent, we consider them in the same island. We only consider up/down/left/right adjacent.

"""


#解决方法:并查集
#参考:https://zhuanlan.zhihu.com/p/54567565
#参考:https://zhuanlan.zhihu.com/p/55604968


"""
Definition for a point.
class Point:
    def __init__(self, a=0, b=0):
        self.x = a
        self.y = b
"""


class UnionFindSet:
    def __init__(self, m, n):
        self.table = [i for i in range(m*n)]
    
    def find_root(self, x):
        if self.table[x] != x:
            return self.find_root(self.table[x])
        return self.table[x]
    
    def merge(self, x, y):
        x_root = self.find_root(x)
        y_root = self.find_root(y)
        self.table[x_root] = y_root
        

class Solution:
    """
    @param n: An integer
    @param m: An integer
    @param operators: an array of point
    @return: an integer array
    """
    def numIslands2(self, n, m, operators):
        # write your code here
        if n==0 or m==0 or len(operators)==0:
            return []
        def idx(i, j):
            return i*m +j
        direction = [[-1, 0], [1, 0], [0, 1], [0, -1]]
        ret = []
        count = 0
        matrix = [[0]*m for i in range(n)]
        us = UnionFindSet(m, n)
        for item in operators:
            if matrix[item.x][item.y]!=1:
                count += 1
                matrix[item.x][item.y] = 1
                for neb in direction:
                    r = item.x+neb[0]
                    c = item.y+neb[1]
                    if 0<=r<n and 0<=c<m and matrix[r][c]==1:  #附近位置为岛屿时,需要进一步判断,是否该减去之前加上的1
                        x1 = idx(item.x, item.y)
                        x2 = idx(r, c)
                        if us.find_root(x1) != us.find_root(x2):  #如果与附近节点不属于同一片岛屿,需要减1
                            count-=1
                            us.merge(x1, x2)
            ret.append(count)
        return ret
Number of islands II

并查集:

#参考:https://zhuanlan.zhihu.com/p/54567565
#参考:https://zhuanlan.zhihu.com/p/55604968

C8. Other Regular Problems

Best time to buy and sell stock

https://www.lintcode.com/problem/best-time-to-buy-and-sell-stock/description

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    import sys
    def maxProfit(self, prices):
        # write your code here
        if len(prices)==0:
            return 0
        min_price = sys.maxsize
        max_profit = 0
        
        for price in prices:
            min_price = min(min_price, price)
            profit = price - min_price
            max_profit = max(max_profit, profit)
        return max_profit        
        
Stock I

https://www.lintcode.com/problem/best-time-to-buy-and-sell-stock-ii/description

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):
        # write your code here
        size = len(prices)
        if size<=1:
            return 0
        res = 0
        for i in range(1, size):
            if prices[i]>prices[i-1]:
                res += prices[i]-prices[i-1]
        return res
        
Stock II

https://www.lintcode.com/problem/best-time-to-buy-and-sell-stock-iii/description

#coding:utf-8

"""
151. Best Time to Buy and Sell Stock III

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most two transactions.
Example

Example 1

Input : [4,4,6,1,1,4,2,5]
Output : 6

Notice

You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

"""
#思路:动态规划
#参考:https://blog.csdn.net/linhuanmars/article/details/23236995

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):
        # write your code here
        size = len(prices)
        if size<=1:
            return 0
        local_ = [0]*3
        global_ = [0]*3
        for i in range(1, size):
            diff = prices[i]-prices[i-1]
            
            for j in range(2, 0, -1):
                local_[j] = max(global_[j-1]+max(diff, 0), local_[j]+diff)
                global_[j] = max(local_[j], global_[j])
        return global_[-1]


#参考:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/solution/yi-ge-tong-yong-fang-fa-tuan-mie-6-dao-gu-piao-wen/        
class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):
        # write your code here
        if not prices:
            return 0
        size = len(prices)
        k=2
        dp_buy = [[0]*(k+1) for i in range(size)]
        dp_sale = [[0]*(k+1) for i in range(size)]
        for i in range(size):
            for j in range(k, 0, -1):
                if i==0:
                    dp_buy[i][j]=-prices[i]
                else:
                    dp_sale[i][j] = max(dp_sale[i-1][j], dp_buy[i-1][j]+prices[i])
                    dp_buy[i][j] = max(dp_buy[i-1][j], dp_sale[i-1][j-1]-prices[i])
        return dp_sale[size-1][k]
            
Stock III

https://www.lintcode.com/problem/best-time-to-buy-and-sell-stock-iv/description

#coding:utf-8

"""
393. Best Time to Buy and Sell Stock IV

Given an array prices and the i-th element of it represents the price of a stock on the i-th day.

You may complete at most k transactions. What's the maximum profit?
Example

Example 1:

Input: k = 2, prices = [4, 4, 6, 1, 1, 4, 2 ,5]
Output: 6
Explanation: Buy at 4 and sell at 6. Then buy at 1 and sell at 5. Your profit is 2 + 4 = 6.

Example 2:

Input: k = 1, prices = [3, 2, 1]
Output: 0
Explanation: No transaction.

Challenge

O(nk) time. n is the size of prices.
Notice

You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).

"""
#Best Time to Buy and Sell Stock II 和Best Time to Buy and Sell Stock III的综合

class Solution:
    """
    @param K: An integer
    @param prices: An integer array
    @return: Maximum profit
    """
    def maxProfit(self, K, prices):
        # write your code here
        size = len(prices)
        if size<=1 or K==0:
            return 0
        if K>=size:
            return self.multi_transcation(prices)
        else: 
            local_ = [0]*(K+1)
            global_ = [0]*(K+1)
            for i in range(1, size):
                diff = prices[i]-prices[i-1]
                
                for j in range(K, 0, -1):
                    local_[j] = max(global_[j-1]+max(diff, 0), local_[j]+diff)
                    global_[j] = max(local_[j], global_[j])
            return global_[-1]
        
    def multi_transcation(self, prices):
        res = 0
        for i in range(1, len(prices)):
            if prices[i]>prices[i-1]:
                res += prices[i]-prices[i-1]
        return res
Stock IV

https://www.lintcode.com/problem/best-time-to-buy-and-sell-stock-with-transaction-fee/description

I added some notes below to help me understand it:

    Only 1 share of the stock can be bought or sold;
    A stock can be bought or sold for multiple times in one day, but it has to be sold before being bought again;
    The service fee is only charged when stock is sold;
    Cash(i): the cash in hand, if you are not holding the stock at the end of day(i):
        You might be not holding the stock at the end of day(i-1), and do nothing in day(i): a = cash(i-1); or
        You might be holding the stock at the end of day(i-1), and sell it at the end of day(i):
        b = hold(i-1) + prices[i] - fee;
        Choose the greatest one as the value of cash(i) to get the greater potential profit:
        cash(i) = max(a, b) = max(cash(i-1), hold(i-1) + prices[i] - fee);
    Hold(i): the cash in hand, if you are holding the stock at the end of day(i):
        You might be holding the stock at the end of day(i-1), and do nothing in day(i): a = hold(i-1); or
        You might be not holding the stock at the end of day(i-1), and buy it at the end of day(i): b = cash(i-1) - prices[i]; or
        You might be holding the stock at the end of day(i-1), sell it on day(i), and buy it again at the end of day(i):
        c = (hold(i-1) + prices[i] - fee) - prices[i];
        Choose the greatest one as the value of hold(i) to get the greater potential profit:
        hold(i) = max(a,b,c)
        Because max(b, c) = max(cash(i-1), hold(i-1) + prices[i] - fee) - prices[i] = cash(i) - prices[i],
        so hold(i) = max(hold(i-1), cash(i) - prices[i]);
    There is another way to calculate hold(i), which is more straight forward:
        You might be holding the stock at the end of day(i-1), and do nothing in day(i): a = hold(i-1); or
        You might be not holding the stock at the end of day(i-1), and buy it at the end of day(i): b = cash(i-1) - prices[i]; or
        You might be holding the stock at the end of day(i-1), sell it on day(i), and buy it again at the end of day(i):
        c = (hold(i-1) + prices[i] - fee) - prices[i] = hold(i-1) - fee;
        Obviously, a > c, so max(a, c) = a, hold(i) = max(a, b, c) = max(a, b) = max(hold(i-1), cash(i-1) - prices[i])
    The target is to find the maximum profit at the end of day(N): cash(
#coding:utf-8

"""
1000. Best Time to Buy and Sell Stock with Transaction Fee

Given an array of integers prices, for which the i-th element is the price of a given stock on day i; and a non-negative integer fee representing a transaction fee. (You need to pay fee only on selling.)

You can complete as many transactions as you like, but you need to pay the transaction fee for each transaction. You can not buy more than 1 share of a stock at a time (ie. you must sell the stock share before you buy again.)

Return the maximum profit you can make.
Example

Example 1:

Input: prices = [1, 3, 2, 8, 4, 9], fee = 2
Output: 8
Explanation: The maximum profit can be achieved by:
  Buying  at prices[0] = 1
  Selling at prices[3] = 8
  Buying  at prices[4] = 4
  Selling at prices[5] = 9
  The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

Example 2:

Input: prices = [1, 4, 6, 2, 8, 3, 10, 14], fee = 3
Output: 13

Notice

0 < prices.length <= 50000.
0 < prices[i] < 50000.
0 <= fee < 50000.

"""

"""
思路:https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/solution/
I added some notes below to help me understand it:
    Only 1 share of the stock can be bought or sold;
    A stock can be bought or sold for multiple times in one day, but it has to be sold before being bought again;
    The service fee is only charged when stock is sold;
    Cash(i): the cash in hand, if you are not holding the stock at the end of day(i):
        You might be not holding the stock at the end of day(i-1), and do nothing in day(i): a = cash(i-1); or
        You might be holding the stock at the end of day(i-1), and sell it at the end of day(i):
        b = hold(i-1) + prices[i] - fee;
        Choose the greatest one as the value of cash(i) to get the greater potential profit:
        cash(i) = max(a, b) = max(cash(i-1), hold(i-1) + prices[i] - fee);
    Hold(i): the cash in hand, if you are holding the stock at the end of day(i):
        You might be holding the stock at the end of day(i-1), and do nothing in day(i): a = hold(i-1); or
        You might be not holding the stock at the end of day(i-1), and buy it at the end of day(i): b = cash(i-1) - prices[i]; or
        You might be holding the stock at the end of day(i-1), sell it on day(i), and buy it again at the end of day(i):
        c = (hold(i-1) + prices[i] - fee) - prices[i];
        Choose the greatest one as the value of hold(i) to get the greater potential profit:
        hold(i) = max(a,b,c)
        Because max(b, c) = max(cash(i-1), hold(i-1) + prices[i] - fee) - prices[i] = cash(i) - prices[i],
        so hold(i) = max(hold(i-1), cash(i) - prices[i]);
    There is another way to calculate hold(i), which is more straight forward:
        You might be holding the stock at the end of day(i-1), and do nothing in day(i): a = hold(i-1); or
        You might be not holding the stock at the end of day(i-1), and buy it at the end of day(i): b = cash(i-1) - prices[i]; or
        You might be holding the stock at the end of day(i-1), sell it on day(i), and buy it again at the end of day(i):
        c = (hold(i-1) + prices[i] - fee) - prices[i] = hold(i-1) - fee;
        Obviously, a > c, so max(a, c) = a, hold(i) = max(a, b, c) = max(a, b) = max(hold(i-1), cash(i-1) - prices[i])
    The target is to find the maximum profit at the end of day(N): cash(N);

"""

class Solution:
    """
    @param prices: a list of integers
    @param fee: a integer
    @return: return a integer
    """
    def maxProfit(self, prices, fee):
        # write your code here
        size = len(prices)
        if size<=1:
            return 0
        cash = 0
        hold = -prices[0]
        for i in range(1, size):
            cash = max(cash, hold+prices[i]-fee)
            hold = max(hold, cash-prices[i])
        return cash
       
Stock with Transaction Fee

 

参考:

   https://blog.csdn.net/qq_31552435/article/details/52247817

  https://blog.csdn.net/linhuanmars/article/details/23236995

  https://blog.csdn.net/qq_38702697/article/details/82762654

  https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/solution/

 

 House Robber

https://www.lintcode.com/problem/house-robber/description

#coding:utf-8

"""
392. House Robber

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
Example

Example 1:

Input: [3, 8, 4]
Output: 8
Explanation: Just rob the second house.

Example 2:

Input: [5, 2, 1, 3]
Output: 8
Explanation: Rob the first and the last house.

Challenge

O(n) time and O(1) memory.

"""

class Solution:
    """
    @param A: An array of non-negative integers
    @return: The maximum amount of money you can rob tonight
    """
    def houseRobber(self, A):
        # write your code here
        if len(A)==0:
            return 0
        size = len(A)
        max_money = [0]*size
        max_money[0] = A[0]
        for i in range(1, size):
            if i==1:
                max_money[i] = max(max_money[i-1], A[1])
            else:
                max_money[i] = max(max_money[i-2]+A[i], max_money[i-1])
        return max_money[-1]


#O(1) memory        
class Solution:
    """
    @param A: An array of non-negative integers
    @return: The maximum amount of money you can rob tonight
    """
    def houseRobber(self, A):
        # write your code here
        if len(A)==0:
            return 0
        size = len(A)
        if size==1:
            return A[0]
        if size== 2:
            return max(A[0], A[1])
        dp_2 = A[0]
        for i in range(1, size):
            if i==1:
                dp_1 = max(dp_2, A[1])
            else:
                dp = max(dp_2+A[i], dp_1)
                dp_2 = dp_1
                dp_1 = dp
                
        return dp
House Robber I

https://www.lintcode.com/problem/house-robber-ii/description

#coding:utf-8

"""
534. House Robber II  (题目含义参见:https://www.lintcode.com/problem/house-robber/description)

After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
Example

Example1

Input:  nums = [3,6,4]
Output: 6

Example2

Input:  nums = [2,3,2,3]
Output: 6

Notice

This is an extension of House Robber.

"""

class Solution:
    """
    @param nums: An array of non-negative integers.
    @return: The maximum amount of money you can rob tonight
    """
    def houseRobber2(self, nums):
        # write your code here
        size = len(nums)
        if size==0:
            return 0
        if size==1:
            return nums[0]
        if size==2:
            return max(nums[0], nums[1])
        ret1 =[0]*size
        ret2 = [0]*(size-1)
        ret1[0], ret1[1] = 0, nums[1]
        ret2[0], ret2[1] = nums[0], max(nums[0], nums[1])
        for i in range(2, size):
            if i<size-1:
                ret2[i] = max(ret2[i-2]+nums[i], ret2[i-1])
            ret1[i] = max(ret1[i-2]+nums[i], ret1[i-1])
        return max(ret1[-1], ret2[-1])
        
House Robber II

https://www.lintcode.com/problem/house-robber-iii/description

#coding:utf-8

"""
535. House Robber III

The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.

Determine the maximum amount of money the thief can rob tonight without alerting the police.
Example

Example1

Input:  {3,2,3,#,3,#,1}
Output: 7
Explanation:
Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
  3
 / \
2   3
 \   \ 
  3   1

Example2

Input:  {3,4,5,1,3,#,1}
Output: 9
Explanation:
Maximum amount of money the thief can rob = 4 + 5 = 9.
    3
   / \
  4   5
 / \   \ 
1   3   1

Notice

This problem is the extention of House Robber and House Robber II
{3,2,3,#,3,#,1}

"""


#思路:递归调用每一个根节点,分为取根节点,和取左右节点两种情况
#参考:https://www.jiuzhang.com/solutions/house-robber-iii/#tag-highlight-lang-python

"""
Definition of TreeNode:
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: The root of binary tree.
    @return: The maximum amount of money you can rob tonight
    """
    def houseRobber3(self, root):
        # write your code here
        rob, not_rob = self.helper(root)
        return max(rob, not_rob)
    
    def helper(self, root):
        if root == None:
            return (0, 0)
        left_rob, left_not_rob = self.helper(root.left)
        right_rob, right_not_rob = self.helper(root.right)
        root_rob = root.val + left_not_rob + right_not_rob
        root_not_rob = max(left_rob, left_not_rob) + max(right_rob, right_not_rob)
        
        return root_rob, root_not_rob
House Robber III

Permutation index

https://www.lintcode.com/problem/permutation-index/description

#coding:utf-8

"""
197. Permutation Index

Given a permutation which contains no repeated number, find its index in all the permutations of these numbers, which are ordered in lexicographical order. The index begins at 1.
Example

Example 1:

Input:[1,2,4]
Output:1

Example 2:

Input:[3,2,1]
Output:6

"""
#思路:
#https://blog.csdn.net/Marvin_Huoshan/article/details/80540917
# 为了更加直观的看清楚我们选择一个大点的数组[6,8,4,7,5,3,2]这个数组,他的第一排序是[2,3,4,5,6,7,8]对吧,
# 然后首先拿到待计算排序的第一个元素6,那么在6之前比他小的元素有几个呢? 是不是有2,3,4,5这4个,
# 确定了第一个元素后,其他剩下的7-1=6个元素进行全排列,共有6!=720种,所以一共有4*(7-1)!种。
# 但是计算第二个元素的时候要小心了。现在第2个元素是8,比8小的元素有几个呢,6个。错!!!,
# 因为第一个元素已经确定了,所以应该是还有5个,那么此时剩下的元素进行全排列就有5*(7-2)!种 
# 下面是每一位上元素的所有排列情况 
# 6 –> 4x(7-1)!种 
# 8 –> 5x(7-2)!种 
# 4 –> 2x(7-3)!种 
# 7 –> 3x(7-4)!种 
# 5 –> 2x(7-5)!种 
# 3 –> 1x(7-6)!种 
# 2 –> 0x(7-7)!种 
# 最后再加上一个第1排序

class Solution:
    """
    @param A: An array of integers
    @return: A long integer
    """
    def permutationIndex(self, A):
        # write your code here
        size = len(A)
        if size==0:
            return None
        index = 1  
        fac = 1
        for i in range(size-1, -1, -1):
            count = 0
            for j in range(i+1, size):
                if A[j]<A[i]:
                    count += 1  #比自己小的数字个数
            index += (count*fac)
            fac *= (size-i)      #阶乘累乘
        return index
Permutation index I

https://www.lintcode.com/problem/permutation-index-ii/description

#coding:utf-8

"""
198. Permutation Index II

Given a permutation which may contain repeated numbers, find its index in all the permutations of these numbers, which are ordered in lexicographical order. The index begins at 1.
Example

Example 1:

Input :[1,4,2,2]
Output:3

Example 2:

Input :[1,6,5,3,1]
Output:24

"""
#思路:和Permutation IndexI思想一样,只是这道题有重复元素,有无重复元素最大的区别在于原来的1!, 2!, 3!...等需要除以重复元素个数的阶乘。
#134353 (对于这6个数的全排列,3出现了三次,三个位置处的3可以随意排列,而三个3的排列共有3*2*1总,故会重复6次)

class Solution:
    """
    @param A: An array of integers
    @return: A long integer
    """
    def permutationIndexII(self, A):
        # write your code here
        size = len(A)
        if size==0:
            return 1
        frac, ret, frac_rep = 1, 1, 1 
        repeated_dict = {}
        for i in range(size-1, -1, -1):
            if A[i] not in repeated_dict:
                repeated_dict[A[i]] = 0
            repeated_dict[A[i]] += 1
            if repeated_dict[A[i]]>1:
                frac_rep *= repeated_dict[A[i]]
            counter = 0
            for j in range(i+1, size):
                if A[i]>A[j]:
                    counter += 1
            ret += (counter*frac//frac_rep)
            frac *= (size-i)
        return ret
Permutation Index II

Combination Sum

https://www.lintcode.com/problem/combination-sum/description

#coding:utf-8

"""
135. Combination Sum
Description

    Given a set of candidtate numbers candidates and a target number target. Find all unique combinations in candidates where the numbers sums to target.

    The same repeated number may be chosen from candidates unlimited number of times.

        All numbers (including target) will be positive integers.
        Numbers in a combination a1, a2, … , ak must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak)
        Different combinations can be in any order.
        The solution set must not contain duplicate combinations.

Example 1:

    Input: candidates = [2, 3, 6, 7], target = 7
    Output: [[7], [2, 2, 3]]

Example 2:

    Input: candidates = [1], target = 3
    Output: [[1, 1, 1]]

"""

#参考:https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/

class Solution:
    """
    @param candidates: A list of integers
    @param target: An integer
    @return: A list of lists of integers
    """
    def combinationSum(self, candidates, target):
        # write your code here
        size = len(candidates)
        if size==0:
            return []
        candidates.sort()  #排序保证最后数组按序排列
        ret=[]
        self.dfs(candidates,0,size,target,ret)
        return ret
        
    def dfs(self,candidates,begin,size,target,ret,temp=[]):
        if target==0:
            if temp not in ret:
                ret.append(temp[:])
            return
        if target<0:
            return
        for i in range(begin,size):
            temp.append(candidates[i])
            self.dfs(candidates,i,size,target-candidates[i],ret,temp)  #从i开始往后选下一个数据,保证避免出现重复
            temp.pop()
Combination Sum I

https://www.lintcode.com/problem/combination-sum-ii/description

#coding:utf-8

"""
153. Combination Sum II
Description

Given an array num and a number target. Find all unique combinations in num where the numbers sum to target.

    Each number in num can only be used once in one combination.
    All numbers (including target) will be positive integers.
    Numbers in a combination a1, a2, … , ak must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak)
    Different combinations can be in any order.
    The solution set must not contain duplicate combinations.


Example 1:

    Input: num = [7,1,2,5,1,6,10], target = 8
    Output: [[1,1,6],[1,2,5],[1,7],[2,6]]

Example 2:

    Input: num = [1,1,1], target = 2
    Output: [[1,1]]
    Explanation: The solution set must not contain duplicate combinations.

"""

class Solution:
    """
    @param num: Given the candidate numbers
    @param target: Given the target number
    @return: All the combinations that sum to target
    """
    def combinationSum2(self, num, target):
        # write your code here
        if len(num)==0:
            return []
        ret=[]
        self.dfs(num,0,target,ret)
        return ret

    def dfs(self,num,i,target,ret,temp=[]):
        if target==0:
            sort_temp=sorted(temp)
            if sort_temp not in ret:
                ret.append(sort_temp)
            return
        if target<0:
            return
            
        if i==len(num):
            return 
        while i<len(num):
            temp.append(num[i])
            self.dfs(num,i+1,target-num[i],ret,temp)
            temp.pop()
            i+=1
if __name__=="__main__":
    s=Solution()
    print(s.combinationSum2(num = [7,1,2,5,1,6,10], target = 8))
    print(s.combinationSum2(num = [1,1,1], target = 2))
    print(s.combinationSum2(num = [2,3,6,7], target = 7))
    
Combiation Sum II

https://www.lintcode.com/problem/combination-sum-iv/description

#coding:utf-8
"""
564. Combination Sum IV

Given an integer array nums with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.
Example

Example1

Input: nums = [1, 2, 4], and target = 4
Output: 6
Explanation:
The possible combination ways are:
[1, 1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[2, 1, 1]
[2, 2]
[4]

Example2

Input: nums = [1, 2], and target = 4
Output: 5
Explanation:
The possible combination ways are:
[1, 1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[2, 1, 1]
[2, 2]

Notice

A number in the array can be used multiple times in the combination.
Different orders are counted as different combinations.

"""
#动态规划,完全背包问题(0/1 背包)
#参考:https://www.jiuzhang.com/solutions/combination-sum-iv/


class Solution:
    """
    @param nums: an integer array and all positive numbers, no duplicates
    @param target: An integer
    @return: An integer
    """
    def backPackVI(self, nums, target):
        # write your code here
        if len(nums)==0:
            return 0
        dp = [0]*(target+1)
        dp[0] =1
        for i in range(1, target+1):
            for j in range(0, len(nums)):
                if i>=nums[j]:
                    dp[i] += dp[i-nums[j]]
        return dp[target]
        
if __name__ == "__main__":
    s = Solution()
    nums = [1,2,4]
    target = 4
    s.backPackVI(nums, target)
Combination Sum IV

 

Linked list cycle

https://www.lintcode.com/problem/linked-list-cycle/description

#coding:utf-8

"""
102. Linked List Cycle
Given a linked list, determine if it has a cycle in it.


Example

    Example 1:
        Input: 21->10->4->5,  then tail connects to node index 1(value 10).
        Output: true
        
    Example 2:
        Input: 21->10->4->5->null
        Output: false
    
    ```

Challenge

Follow up:
Can you solve it without using extra space?
"""

"""
Definition of ListNode
class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
"""

class Solution:
    """
    @param head: The first node of linked list.
    @return: True if it has a cycle, or false
    """
    def hasCycle(self, head):
        # write your code here
        if not head or not head.next:
            return False
        slow = head.next
        fast = head.next.next
        while fast and fast.next:
            if fast == slow:
                return True
            fast = fast.next.next
            slow = slow.next
Linked List Cycle I

https://www.lintcode.com/problem/linked-list-cycle-ii/description

#coding:utf-8
"""
103. Linked List Cycle II

Given a linked list, return the node where the cycle begins.

If there is no cycle, return null.
Example

Example 1:

Input:null,no cycle
Output:no cycle
Explanation:
List is null,so no cycle.

Example 2:

Input:-21->10->4->5,tail connects to node index 1
Output:10
Explanation:
The last node 5 points to the node whose index is 1, which is 10, so the entrance of the ring is 10

Challenge

Follow up:

Can you solve it without using extra space?

"""
"""
Definition of ListNode
class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
"""

class Solution:
    """
    @param head: The first node of linked list.
    @return: The node where the cycle begins. if there is no cycle, return null
    """
    def detectCycle(self, head):
        # write your code here
        if head==None or head.next==None:
            return None
        fast = slow = head
        cycle = False
        while fast and fast.next and not cycle:
            fast = fast.next.next
            slow = slow.next
            if fast is slow:
                cycle = True
        if cycle:
            fast = head
            while fast is not slow:
                fast = fast.next
                slow = slow.next
            return fast
        else:
            return None
Linked List cycle II

 Calculator I

https://www.lintcode.com/problem/basic-calculator/description (Calculator I)

https://www.lintcode.com/problem/basic-calculator-ii/description  (Calculator II)

https://www.lintcode.com/problem/basic-calculator-iii/description(Calculator III)

#coding:utf-8

"""
849. Basic Calculator III
Implement a basic calculator to evaluate a simple expression string.

The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces .

The expression string contains only non-negative integers, +, -, *, / operators , open ( and closing parentheses ) and empty spaces . The integer division should truncate toward zero.

You may assume that the given expression is always valid. All intermediate results will be in the range of [-2147483648, 2147483647]
Example

Example 1:

Input:"1 + 1"
Output:2
Explanation:1 + 1 = 2

Example 2:

Input:" 6-4 / 2 "
Output:4
Explanation:4/2=26-2=4

Notice

Do not use the eval built-in library function.

"""

class Solution:
    """
    @param s: the expression string
    @return: the answer
    """
    def calculate(self, s):
        # Write your code here
        if not s:
            return None
        postfix = self.pre_to_post(s)
        temp = []
        for token in postfix:
            if token in "+-*/":
                operand2 = temp.pop()
                operand1 = temp.pop()
                result = self.do_math(operand1, operand2, token)
                temp.append(result)
            else:
                temp.append(int(token))
        return temp.pop()
                
    def pre_to_post(self, s):
        import string
        digits = string.digits
        operators = {"(":1,"+":2,"-":2, "*":3, "/":3}
        stack = []
        que = []
        size = len(s)
        multi_digit = ""
        for i in range(size):
            if s[i]== " ":
                continue
            if s[i]=="(":
                stack.append(s[i])
            elif s[i] in digits:
                multi_digit += s[i]
                if i<size-1 and s[i+1] in digits:
                    continue
                que.append(multi_digit)
                multi_digit = ""
            elif s[i] in operators.keys():
                while stack and operators[stack[-1]]>=operators[s[i]]:
                    que.append(stack.pop())
                stack.append(s[i])
            elif s[i]==")":
                while stack and stack[-1]!="(":
                    que.append(stack.pop())
                stack.pop()
        while stack:
            que.append(stack.pop())
        return que
            
        
    def do_math(self, operand1, operand2, token):
        if token=='*':
            return operand1 * operand2
        elif token=='/':
            return operand1 // operand2
        elif token=='+':
            return operand1 + operand2
        else:
            return operand1 - operand2
Caculator III

 C9. CV specific problems

 

 Range sum 1d immutuable

https://www.lintcode.com/problem/range-sum-query-immutable/description

#coding:utf-8

"""
943. Range Sum Query - Immutable

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
Example

Example1

Input: nums = [-2, 0, 3, -5, 2, -1]
sumRange(0, 2)
sumRange(2, 5)
sumRange(0, 5)
Output:
1
-1
-3
Explanation: 
sumRange(0, 2) -> (-2) + 0 + 3 = 1
sumRange(2, 5) -> 3 + (-5) + 2 + (-1) = -1
sumRange(0, 5) -> (-2) + 0 + 3 + (-5) + 2 + (-1) = -3

Example2

Input: 
nums = [-4, -5]
sumRange(0, 0)
sumRange(1, 1)
sumRange(0, 1)
sumRange(1, 1)
sumRange(0, 0)
Output: 
-4
-5
-9
-5
-4
Explanation: 
sumRange(0, 0) -> -4
sumRange(1, 1) -> -5
sumRange(0, 1) -> (-4) + (-5) = -9
sumRange(1, 1) -> -5
sumRange(0, 0) -> -4

Notice

    You may assume that the array does not change.
    There are many calls to sumRange function.

"""
#思路:积分图

class NumArray(object):

    def __init__(self, nums):
        """
        :type nums: List[int]
        """
        size = len(nums)
        self.nums = nums
        if size>0:
            self.range_sum=[0]*(size+1)
            for i in range(1, size+1):
                self.range_sum[i] = self.range_sum[i-1]+nums[i-1]
        

    def sumRange(self, i, j):
        """
        :type i: int
        :type j: int
        :rtype: int
        """
        return self.range_sum[j+1]-self.range_sum[i]


# Your NumArray object will be instantiated and called as such:
# obj = NumArray(nums)
# param_1 = obj.sumRange(i,j)
Range Sum Id immutable

Range sum 1d mutuable

https://www.lintcode.com/problem/range-sum-query-mutable/description

#coding:utf-8

"""
840. Range Sum Query - Mutable

Given an integer array nums, and then you need to implement two functions:

    update(i, val) Modify the element whose index is i to val.
    sumRange(l, r) Return the sum of elements whose indexes are in range of [l,r][l, r][l,r].

Example

Example 1:

Input: 
  nums = [1, 3, 5]
  sumRange(0, 2)
  update(1, 2)
  sumRange(0, 2)
Output:
  9
  8

Example 2:

Input:
  nums = [0, 9, 5, 7, 3]
  sumRange(4, 4)
  sumRange(2, 4)
  update(4, 5)
  update(1, 7)
  update(0, 8)
  sumRange(1, 2)
Output:
  3
  15
  12

Notice

    The array is only modifiable by the update function.
    You may assume the number of calls to update and sumRange function is distributed evenly.

"""
#思路:分段树
#参考:https://leetcode.com/problems/range-sum-query-mutable/solution/

class NumArray:

    def __init__(self, nums):
        """
        :type nums: List[int]
        """
        self.size = len(nums)
        if self.size>0:
            self.tree = [0]*(2*self.size)
            for i in range(self.size, 2*self.size):
                self.tree[i] = nums[i-self.size]
            for j in range(self.size-1, 0, -1):    #注意tree[0]为多出来的空元素,因为i=0时,2*i也为0
                self.tree[j] = self.tree[2*j] + self.tree[2*j+1]

    def update(self, i, val):
        """
        :type i: int
        :type val: int
        :rtype: void
        """
        i+=self.size
        self.tree[i] = val
        while i>0:
            left, right = i, i
            if i&1:
                left = i -1
            else:
                right = i + 1
            self.tree[i//2] = self.tree[left] + self.tree[right]
            i = i//2

    def sumRange(self, i, j):
        """
        :type i: int
        :type j: int
        :rtype: int
        """
        i += self.size
        j += self.size
        sum=0
        while i<=j:
            if i&1:
                sum += self.tree[i]
                i += 1
            if not j&1:
                sum += self.tree[j]
                j -= 1
            i = i//2        
            j = j//2
        return sum
# Your NumArray object will be instantiated and called as such:
# obj = NumArray(nums)
# obj.update(i,val)
# param_2 = obj.sumRange(i,j)
Range sum 1d mutuable

Range sum 2d immutable

https://www.lintcode.com/problem/range-sum-query-2d-immutable/description

#coding:utf-8

"""
665. Range Sum Query 2D - Immutable


Given a 2D matrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).
Example

Example1

Input:
[[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]
sumRegion(2, 1, 4, 3)
sumRegion(1, 1, 2, 2)
sumRegion(1, 2, 2, 4)
Output:
8
11
12
Explanation:
Given matrix = 
[
  [3, 0, 1, 4, 2],
  [5, 6, 3, 2, 1],
  [1, 2, 0, 1, 5],
  [4, 1, 0, 1, 7],
  [1, 0, 3, 0, 5]
]
sumRegion(2, 1, 4, 3) = 2 + 0 + 1 + 1 + 0 + 1 + 0 + 3 + 0 = 8
sumRegion(1, 1, 2, 2) = 6 + 3 + 2 + 0 = 11
sumRegion(1, 2, 2, 4) = 3 + 2 + 1 + 0 + 1 + 5 = 12

Example2

Input:
[[3,0],[5,6]]
sumRegion(0, 0, 0, 1)
sumRegion(0, 0, 1, 1)
Output:
3
14
Explanation:
Given matrix = 
[
  [3, 0],
  [5, 6]
]
sumRegion(0, 0, 0, 1) = 3 + 0 = 3
sumRegion(0, 0, 1, 1) = 3 + 0 + 5 + 6 = 14

Notice

    You may assume that the matrix does not change.
    There are many calls to sumRegion function.
    You may assume that row1 ≤ row2 and col1 ≤ col2.

[[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]
sumRegion(2, 1, 4, 3)
sumRegion(1, 1, 2, 2)
sumRegion(1, 2, 2, 4)

"""

#积分图

class NumMatrix:
    """
    @param: matrix: a 2D matrix
    """
    def __init__(self, matrix):
        # do intialization if necessary
        if len(matrix) and len(matrix[0]):
            rows, cols = len(matrix), len(matrix[0])
            self.matrix = matrix
            self.col_sum = [0]*cols
            self.range_sum = [[0]*(cols+1) for i in range(rows+1)]
            for i in range(1, rows+1):
                for j in range(1, cols+1):
                    self.range_sum[i][j] = self.matrix[i-1][j-1]-self.range_sum[i-1][j-1]+self.range_sum[i][j-1]+self.range_sum[i-1][j]
                    

    """
    @param: row1: An integer
    @param: col1: An integer
    @param: row2: An integer
    @param: col2: An integer
    @return: An integer
    """
    def sumRegion(self, row1, col1, row2, col2):
        # write your code here
        area = self.range_sum[row2+1][col2+1]-self.range_sum[row2+1][col1]-self.range_sum[row1][col2+1]+self.range_sum[row1][col1]
        return area

# Your NumMatrix object will be instantiated and called as such:
# obj = NumMatrix(matrix)
# param_1 = obj.sumRegion(row1,col1,row2,col2)
Range sum 2d immutable

Range sum 2d immutable

 https://www.lintcode.com/problem/range-sum-query-2d-mutable/description

 

Sliding window Maximum

https://www.lintcode.com/problem/sliding-window-maximum/description

#coding:utf-8

"""
362. Sliding Window Maximum

Given an array of n integer with duplicate number, and a moving window(size k), move the window at each iteration from the start of the array, find the maximum number inside the window at each moving.
Example

Example 1:

Input:
[1,2,7,7,8]
3
输出:
[7,7,8]

Explanation:
At first the window is at the start of the array like this `[|1, 2, 7| ,7, 8]` , return the maximum `7`;
then the window move one step forward.`[1, |2, 7 ,7|, 8]`, return the maximum `7`;
then the window move one step forward again.`[1, 2, |7, 7, 8|]`, return the maximum `8`;

Example 2:

Input:
[1,2,3,1,2,3]
5
Output:
[3,3]

Explanation:
At first, the state of the window is as follows: ` [,2,3,1,2,1 | , 3] `, a maximum of ` 3 `;
And then the window to the right one. ` [1, | 2,3,1,2,3 |] `, a maximum of ` 3 `;

Challenge

o(n) time and O(k) memory

"""

#双端队列,队列的最左端总是保存窗口中最大值的index

class Solution:
    """
    @param nums: A list of integers.
    @param k: An integer
    @return: The maximum number inside the window at each moving.
    """
    def maxSlidingWindow(self, nums, k):
        # write your code here
        size = len(nums)
        if not size:
            return []
        index, res = [], []
        for i in range(0, k):
            while index and nums[i]>=nums[index[-1]]:
                index.pop()
            index.append(i)
        for j in range(k, size):
            res.append(nums[index[0]])
            while index and nums[j]>=nums[index[-1]]:
                index.pop()
            while index and index[0]<=j-k:   #保证队列最左端保存的是窗口[j-k+1, j]中的index
                index.pop(0)
            index.append(j)
        res.append(nums[index[0]])
        return res
Sliding window maximum

 

 Convolution: Medain Filter

#coding:utf-8

import heapq
import cv2

#实现图片的中值滤波算法
# 2D median filter with no stride, zero padding

def medain_filter(img, kernel_w, kernel_h):
    """
    img: cv2 matrix
    kernel_w: kernel width
    kernel_h: kernel height
    """
    rows, cols = img.shape[:2]
    for i in range(rows):
        for j in range(cols):
            left = max(0, j-kernel_w//2)
            right = min(cols-1, j+kernel_w//2)
            upper = max(0, i-kernel_h//2)
            lower = min(rows-1, i+kernel_h//2)
            
            #kernel中的像素点放入堆中
            hq = []
            for m in range(upper, lower+1):
                for n in range(left, right+1):
                    heapq.heappush(hq, img[m][n])
            size = (right-left+1)*(lower-upper+1)
            if size&1:  #奇数个元素,取中间值
                for k in range(0, (size+1)//2):
                    median = heapq.heappop(hq)
                img[i][j] = median
            else:  #偶数个元素,取中间两个元素平均值
                for k in range(0, (size+1)//2):
                    median1 = heapq.heappop(hq)
                median2 = heapq.heappop(hq)
                img[i][j] = (median1+median2)//2
    return img

if __name__ == "__main__":
    img = cv2.imread(r"C:\Users\Administrator\Desktop\dog.jpg", 0)
    img2 = medain_filter(img, 3, 3)
    cv2.imshow("img", img)
    cv2.imshow("img2", img2)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
                
            
Median Filter

Convolution: Average Pooling

#coding:utf-8

import cv2

#平均池化算法实现
#Average Pooling with zero padding, stride

def average_pooling(img, kernel_w, kernel_h, stride=1):
    """
    img: cv2 matrix
    kernel_w: kernel width
    kernel_h: kernel height
    stride: sliding length
    """
    rows, cols, channel = img.shape[:]
    for i in range(channel):
        for j in range(0, rows, stride):
            for k in range(0, cols, stride):
                left = max(0, j-kernel_w//2)
                right = min(cols-1, j+kernel_w//2)
                upper = max(0, i-kernel_h//2)
                lower = min(rows-1, i+kernel_h//2)
                
                #计算平均值
                area = (right-left+1)*(lower-upper+1)
                sum = 0
                for m in range(upper, lower+1):
                    for n in range(left, right+1):
                        sum += img[m, n, i]
                        
                img[j, k, i] = sum//area
    return img
    
if __name__ == "__main__":
    img = cv2.imread(r"C:\Users\Administrator\Desktop\dog.jpg")
    img2 = average_pooling(img, 3, 3, 1)
    cv2.imshow("img", img)
    cv2.imshow("img2", img2)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
Average pooling

D Classic Question

 

 Hannoi

Champagne Tower

https://www.lintcode.com/problem/champagne-tower/description

#coding:utf-8

"""
1018. Champagne Tower

We stack glasses in a pyramid, where the first row has 1 glass, the second row has 2 glasses, the third row has 3 glasses and so on until the 100th row. Each glass holds one cup (250ml) of champagne.

Then, some champagne is poured in the first glass at the top. When the top most glass is full, any excess liquid poured will fall equally to the glass immediately to the left and right of it. When those glasses become full, any excess champagne will fall equally to the left and right of those glasses, and so on. (A glass at the bottom row has it's excess champagne fall on the floor.)

For example, after one cup of champagne is poured, the top most glass is full. After two cups of champagne are poured, the two glasses on the second row are half full. After three cups of champagne are poured, those two cups become full - there are 3 full glasses total now. After four cups of champagne are poured, the third row has the middle glass half full, and the two outside glasses are a quarter full, as pictured below.

Now after pouring some non-negative integer cups of champagne, return how full the j-th glass in the i-th row is (both i and j are 0 indexed).
Example

Example 1:

Input: poured = 1, query_glass = 1, query_row = 1
Output: 0.0
Explanation: We poured 1 cup of champange to the top glass of the tower (which is indexed as (0, 0)). There will be no excess liquid so all the glasses under the top glass will remain empty.

Example 2:

Input: poured = 2, query_glass = 1, query_row = 1
Output: 0.5
Explanation: We poured 2 cups of champange to the top glass of the tower (which is indexed as (0, 0)). There is one cup of excess liquid. The glass indexed as (1, 0) and the glass indexed as (1, 1) will share the excess liquid equally, and each will get half cup of champange.

Notice

    poured will be in the range of [0, 10 ^ 9].
    query_glass and query_row will be in the range of [0, 99].

"""

#思路:动态规划,参考https://blog.csdn.net/qq_23523409/article/details/85540095
#dp[i][j] 第i层,第j杯的香槟总数
# 先将总数为sum的香槟放入最顶上的杯子,也就是数组下标为[0][0]的地方香槟总数为sum。假设dp[i][j]为数组下标为[i][j]获得的香槟总数,dp[0][0]=sum。
    # 除dp[0][0]以外,所有值均为0.
    # 如果sum>1,那么剩余的香槟必然溢出到下一层的[i+1][j]和[i+1][j+1]两个位置。
    # 根据题意,等流量的条件,dp[i+1][j]+=(dp[i][j]-1)*0.5,dp[i+1][j+1]+=(dp[i][j]-1)*0.5。
    # 迭代100次必然可以算出所有杯子的状态。(实际只需迭代到需要查询的层数)

class Solution:
    """
    @param poured: an integer
    @param query_row: an integer
    @param query_glass: an integer
    @return: return a double
    """
    def champagneTower(self, poured, query_row, query_glass):
        # write your code here
        if poured==0:
            return 0.0
        dp = [[0.0]*(query_row+1) for i in range(query_row+1)]  
        dp[0][0] = poured
        for i in range(1, query_row+1):
            for j in range(query_row+1):
                if dp[i-1][j-1]>1:    #上一层会溢出到下一层的左右两个杯子
                    dp[i][j-1] += (dp[i-1][j-1] -1)/2
                    dp[i][j] += (dp[i-1][j-1]-1)/2
        if dp[query_row][query_glass]>1:  #大于1表示装满了,会溢出到下一层,此杯状态即为1
            return 1.0
        else:
            return dp[query_row][query_glass]
Champagne Tower

 N-Queens

https://www.lintcode.com/problem/n-queens/description

#coding:utf-8
"""
33. N-Queens

Description

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.


Example 1:

    Input:1
    Output:
       [["Q"]]


Example 2:

    Input:4
    Output:
    [
      // Solution 1
      [".Q..",
       "...Q",
       "Q...",
       "..Q."
      ],
      // Solution 2
      ["..Q.",
       "Q...",
       "...Q",
       ".Q.."
      ]
    ]

"""

class Solution:
    """
    @param: n: The number of queens
    @return: All distinct solutions
    """
    def solveNQueens(self, n):
        # write your code here
        if n==0:
            return 0
        ret=[]
        self.dfs(n, 0, ret)
        return ret
    
    def dfs(self, n, index, ret, temp=[]): 
        if index==n:
            m = self.tomap(n, temp)
            ret.append(m)
        s=[]
        for i in range(index):
            s.append(temp[i]+(index-i))
            s.append(temp[i]-(index-i))
        for i in range(n):
            if i not in (s+temp):
                temp.append(i)
                self.dfs(n,index+1,ret,temp)
                temp.pop()
    
    def tomap(self, n, temp):
        m=[]
        for i in temp:
            line = "."*i+"Q"+"."*(n-i-1)
            m.append(line)
        return m 
N-Queens

 N-Queens

https://www.lintcode.com/problem/n-queens-ii/description

#coding:utf-8
"""
Description
34. N-Queens II

    Follow up for N-Queens problem. (即任意两个皇后都不能处于同一行、同一列或同一斜线上)
    Now, instead outputting board configurations, return the total number of distinct solutions.
Example 1:

    Input: n=1
    Output: 1
    Explanation:
    1:
    1

Example 2:

    Input: n=4
    Output: 2
    Explanation:
    1:
    0 0 1 0
    1 0 0 0
    0 0 0 1
    0 1 0 0
    2:
    0 1 0 0 
    0 0 0 1
    1 0 0 0
    0 0 1 0

"""
class Solution:
    """
    @param n: The number of queens.
    @return: The total number of distinct solutions.
    """
    def totalNQueens(self, n):
        # write your code here
        if n==0:
            return 0
        self.num=0
        self.dfs(n,0)
        return self.num
    
    def dfs(self, n, index, ret=[]):
        if index==n:
            self.num+=1
            return
        temp=[]
        for i in range(index):
            temp.append(ret[i]+(index-i))
            temp.append(ret[i]-(index-i))
        for i in range(n):
            if i not in (temp+ret):
                ret.append(i)
                self.dfs(n,index+1,ret)
                ret.pop()
            
        
N-Queens II

Minesweeper

https://www.lintcode.com/problem/minesweeper/description

#coding:utf-8

"""
1189. 扫雷游戏

让我们一起来玩扫雷游戏!

给定一个代表游戏板的二维字符矩阵。 'M' 代表一个未挖出的地雷,'E' 代表一个未挖出的空方块,'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字('1''8')表示有多少地雷与这块已挖出的方块相邻,'X' 则表示一个已挖出的地雷。

现在给出在所有未挖出的方块中('M'或者'E')的下一个点击位置(行和列索引),根据以下规则,返回相应位置被点击后对应的面板:

    如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'。
    如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的方块都应该被递归地揭露。
    如果一个至少与一个地雷相邻的空方块('E')被挖出,修改它为数字('1''8'),表示相邻地雷的数量。
    如果在此次点击中,若无更多方块可被揭露,则返回面板。

Example

样例 1:

输入: board = ["EEEEE","EEMEE","EEEEE","EEEEE"], Click : [3,0]
输出: ["B1E1B","B1M1B","B111B","BBBBB"]

样例 2:

输入: board = ["B1E1B","B1M1B", "B111B","BBBBB"], Click : [1,2]
输出: ["B1E1B","B1X1B","B111B","BBBBB"]

Notice

1.输入矩阵的宽和高的范围为 [1,50]。
2.点击的位置只能是未被挖出的方块 ('M' 或者 'E'),这也意味着面板至少包含一个可点击的方块。
3.输入面板不会是游戏结束的状态(即有地雷已被挖出)。
4.简单起见,未提及的规则在这个问题中可被忽略。例如,当游戏结束时你不需要挖出所有地雷,考虑所有你可能赢得游戏或标记方块的情况。

"""

"""
题目意思:矩阵都是M和E,碰到M改为X,返回M;碰到E,周边有雷时,改为雷的数量,不用遍历其附件点;周边无雷时,改为“B”,继续遍历其周围的八个点
"""

class Solution:
    """
    @param board: a board
    @param click: the position
    @return: the new board
    """
    def updateBoard(self, board, click):
        # Write your code here
        if not len(board) and not len(board[0]):
            return board
        board = [list(item) for item in board]
        direction = [[1, 0], [1, -1], [1, 1], [0, 1],[-1, 0], [-1, -1], [-1, 1], [0, -1]]
        self.dfs(board, click, direction)
        return ["".join(item) for item in board]
        
    def dfs(self, board, click, direction):
        if not self.is_valid(board, click[0], click[1]):
            return 
        if board[click[0]][click[1]]=="M":
            board[click[0]][click[1]]="X"
            return
        elif board[click[0]][click[1]]=="E":
            count = self.count_mine(board, click, direction)
            if count:
                board[click[0]][click[1]]=str(count)
            else:
                board[click[0]][click[1]]="B"
                for step in direction:
                    r = click[0] + step[0]
                    c = click[1] + step[1]
                    self.dfs(board, [r,c], direction)
    
    def is_valid(self, board, x, y):
        rows, cols = len(board), len(board[0])
        return 0<=x<rows and 0<=y<cols
    
    def count_mine(self,board, cur, direction):
        count = 0
        for step in direction:
            r = cur[0] + step[0]
            c = cur[1] + step[1]
            if self.is_valid(board, r, c):
                if board[r][c]=="M":
                    count+=1
        return count 
        
if __name__=="__main__":
    s = Solution()
    board = ["EEEEE","EEMEE","EEEEE","EEEEE"]
    Click =[3,0]
    print(s.updateBoard(board, Click))
Minesweeper

24 Game

https://www.lintcode.com/problem/24-game/description

#coding:utf-8
"""
739. 24 Game
You have 4 cards each containing a number from 1 to 9. You need to compute whether they could operated through *, /, +, -, (, ) to get the value of 24.
Example

Example 1:

Input:[1, 4, 8, 7]
Output:true
Explanation:8 * (7 - 4) * 1 = 24

Example 2:

Input:[1, 1, 1, 2]
Output:false
Explanation:no way to get 24

Example 3:

Input:[3, 3, 8, 8]
Output:true
Explanation:8 / ( 3 - 8 / 3) = 24

Notice

    The division operator / represents real division, not integer division. so 4 / (1 - 2/3) = 12.
    Every operation done is between two numbers. In particular, we cannot use - as a unary operator. For example, with [1, 1, 1, 1] as input, the expression -1 - 1 - 1 - 1 is not allowed.
    You cannot concatenate numbers together. For example, if the input is [1, 2, 1, 2], we cannot write this as 12 + 12.

"""

#参考:https://leetcode-cn.com/problems/24-game/solution/24dian-you-xi-by-leetcode/

#递归:
class Solution:
    """
    @param nums: 4 cards
    @return: whether they could get the value of 24
    """
    def compute24(self, nums):
        # write your code here
        from operator import add, mul, truediv, sub
        if not nums:
           return False
        if len(nums)==1:
            return abs(nums[0]-24) < 1e-6
        for i in range(len(nums)):
            for j in range(len(nums)):
                if i!=j:
                    B = [nums[k] for k in range(len(nums)) if k!=i and k!=j]
                    for op in [add, mul, truediv, sub]:
                        if (op is add or op is mul) and j>i:
                            continue
                        if op is not truediv or nums[j]:
                            B.append(op(nums[i], nums[j]))
                            if self.compute24(B):
                                return True
                            B.pop()
                            
        return False




#遍历
class Solution:
    """
    @param nums: 4 cards
    @return: whether they could get the value of 24
    """
    def compute24(self, nums):
        # write your code here
        def cal(a,b):
            if a == 0:
                return b,-b,0
            if b == 0:
                return a,-a,0
            return list({a+b,a-b,b-a,a*b,a/b,b/a})
        stack = [[float(item) for item in nums]]
        while (len(stack) > 0):
            tmp_nums = stack.pop()
            if len(tmp_nums) == 1:
                if abs(tmp_nums[0] - 24.0) <= 0.0001:
                    return True
                continue
            l = len(tmp_nums)
            for n1 in range(l - 1):
                for n2 in range(n1 + 1,l):
                    tmp_cals = cal(tmp_nums[n1],tmp_nums[n2])
                    for tmp_cal in tmp_cals:
                        tmp_res = [tmp_cal] + tmp_nums[:n1] + tmp_nums[n1 + 1:n2] + tmp_nums[n2 + 1:]
                        stack.append(tmp_res)
        return False             
24 Game

 

 

E. Bit Operations

 

 Single Number

https://www.lintcode.com/problem/single-number/description

#coding:utf-8

"""
82. Single Number

Given 2 * n + 1 numbers, every numbers occurs twice except one, find it.
Example

Example 1:

Input:[1,1,2,2,3,4,4]
Output:3
Explanation:
Only 3 appears once

Example 2:

Input:[0,0,1]
Output:1
Explanation:
Only 1 appears once

Challenge

One-pass, constant extra space.
Notice

    n≤100
"""

#异或运算,相同的数字异或运算后为0
class Solution:
    """
    @param A: An integer array
    @return: An integer
    """
    def singleNumber(self, A):
        # write your code here
        if not len(A):
            return None
        size = len(A)
        ret = A[0]
        for i in range(1, size):
            ret = ret^A[i]
        return ret
Single Number

Single Number II

https://www.lintcode.com/problem/single-number-ii/description

#coding:utf-8

"""
83. Single Number II

Given 3*n + 1 non-negative integer, every numbers occurs triple times except one, find it.
Example

Example 1:

Input:  [1,1,2,3,3,3,2,2,4,1]
Output:  4

Example 2:

Input: [2,1,2,2]
Output:  1    

Challenge

One-pass, constant extra space.

"""

#思路:三个相同的数相加,不仅其和能被3整除,其二进制位上的每一位也能被3整除(若不考虑进位),以3为例,若使用不进位加法,三个3相加的结果为:0011+0011+0011=0033
#因此利用位运算,int有32位,用一个长度为32的数组记录每个数字的所有位中1出现的次数,如果这个数字出现3次,则与这个数字对应的每一位上的1也出现三次。最后将数组每一位均对3取余,最后得到的就是要求的数字。


class Solution:
    """
    @param A: An integer array
    @return: An integer
    """
    def singleNumberII(self, A):
        # write your code here
        if not len(A):
            return None
        size = len(A)
        ret = 0
        bits = [0]*32
        for i in range(32):
            for j in range(size):
                bits[i] = bits[i] + ((A[j]>>i) & 1)  #i位上比特为1的数字个数
            bits[i] = bits[i]%3                #i位上比特为1的数字若出现三次的倍数,则余数为0
            ret = ret | (bits[i]<<i)
        return ret 
Single Number II

Single Number III

https://www.lintcode.com/problem/single-number-iii/description

#coding:utf-8

"""
84. Single Number III
Given 2*n + 2 numbers, every numbers occurs twice except two, find them.
Example

Example 1:
    Input:  [1,2,2,3,4,4,5,3]
    Output:  [1,5]

Example 2:
    Input: [1,1,2,3,4,4]
    Output:  [2,3]
    

Challenge

O(n) time, O(1) extra space.

"""

#思路:对2*n + 2数字进行异或,相同的数字异或为0,假设最后两个只出现一次的数分别为x1, x2,那么异或最后的结果为x1 ^ x2,可以根据x1 ^ x2 ^ x1 = x2求得x2, 同理可得x_1
#那么问题是如何找到x1, x2, 有点死循环了?
#由于x1, x2不相等,那么其异或结果肯定有一个比特位为1,假设为k位,那么可以根据第k位是否为1,将2*n + 2个数字分成两组;
#对于这两组,一组肯定包含x1,组内其他数字肯定两两相同,组内全部异或即得到x1; 另一组同理可得x2

class Solution:
    """
    @param A: An integer array
    @return: An integer array
    """
    def singleNumberIII(self, A):
        # write your code here
        if not len(A):
            return None
        size = len(A)
        ans = A[0]
        for i in range(1, size):
            ans = ans^A[i]
        k = 0
        ans1, ans2 =ans, ans
        while not ans&1:
            k+=1
            ans >>= 1
        for i in range(0, size):
            kbit = ((A[i]>>k) & 1)
            if kbit:
                ans1 ^= A[i]
            else:
                ans2 ^= A[i]
        return [ans1, ans2]
Single Number III

Single Number IV

 https://www.lintcode.com/problem/single-number-iv/description

#coding:utf-8

"""
824. Single Number IV

Give an array, all the numbers appear twice except one number which appears once and all the numbers which appear twice are next to each other. Find the number which appears once.
Example

Example 1:

Input: [3,3,2,2,4,5,5]
Output: 4
Explanation: 4 appears only once.

Example 2:

Input: [2,1,1,3,3]
Output: 2
Explanation: 2 appears only once.

"""
#注意末尾元素

class Solution:
    """
    @param nums: The number array
    @return: Return the single number
    """
    def getSingleNumber(self, nums):
        # Write your code here
        if not len(nums):
            return None
        for i in range(0, len(nums)-1, 2):
            if nums[i]!=nums[i+1]:
                return nums[i]
        return nums[-1]
                
Single Number IV

 

Hamming Distance

https://www.lintcode.com/problem/hamming-distance/description

#coding:utf-8

"""
835. Hamming Distance

The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
Given two integers x and y, calculate the Hamming distance.
Example

Example1

Input: x = 1 and y = 4
Output: 2
Explanation:
The binary representation of 1 is 001
The binary representation of 4 is 100
There are 2 different bits

Example2

Input: x = 5 and y = 2
Output: 3
Explanation:
The binary representation of 5 is 101
The binary representation of 2 is 010
There are 3 different bits

Notice

0 ≤ x, y < 231

"""
#异或运算,不同的bit位为1

class Solution:
    """
    @param x: an integer
    @param y: an integer
    @return: return an integer, denote the Hamming Distance between two integers
    """
    def hammingDistance(self, x, y):
        # write your code here
        ans = x^y
        i = 0
        while ans:
            if ans&1:
                i += 1
            ans >>= 1
        return i
Hamming Distance

 Total Hamming Distance

https://www.lintcode.com/problem/total-hamming-distance/description

class Solution:
    """
    @param nums: the gievn integers
    @return: the total Hamming distance between all pairs of the given numbers
    """
    def totalHammingDistance(self, nums):
        # Write your code here
        if not len(nums):
            return 0
        size = len(nums)
        bits = [0]*32
        ret = 0
        for i in range(32):
            for j in range(size):
                bits[i] += ((nums[j]>>i) & 1)
            ret += bits[i]*(size-bits[i])
        return ret
        
Total Hamming Distance

 

 

 

F.动态规划

 

Longest Common Subsequence

 https://www.lintcode.com/problem/longest-common-subsequence/description

#coding:utf-8

"""
77. Longest Common Subsequence

Given two strings, find the longest common subsequence (LCS).

Your code should return the length of LCS.
Example

Example 1:
    Input:  "ABCD" and "EDCA"
    Output:  1
    
    Explanation:
    LCS is 'A' or  'D' or 'C'


Example 2:
    Input: "ABCD" and "EACB"
    Output:  2
    
    Explanation: 
    LCS is "AC"

Clarification

What's the definition of Longest Common Subsequence?

    https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
    http://baike.baidu.com/view/2020307.htm

"""

#动态规划问题:

class Solution:
    """
    @param A: A string
    @param B: A string
    @return: The length of longest common subsequence of A and B
    """
    def longestCommonSubsequence(self, A, B):
        # write your code here
        if not len(A) or not len(B):
            return 0
        length1, length2 = len(A), len(B)
        dp = [[0]*(length1+1) for i in range(length2+1)]
        for i in range(1, length1+1):
            for j in range(1, length2+1):
                if A[i-1]==B[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])
        return dp[length1][length2]
Longest Common Subsequence

 

#coding:utf-8

"""
F2. 硬币翻转(红绿灯问题):
假设有一组硬币,材质非均匀, 因而它们各自抛出后正面朝上的概率不同,假设为 p1,p2,…,pn 。
问:当依次抛掷共n次后, 出现k次正面朝上的概率是多少 

"""

def get_coin_prob(prob_list, k):
    """
    prob_list: n块硬币正面朝上的概率
    k: n块硬币各抛依次,出现k次正面朝上
    """
    if not len(prob_list):
        return 0
    n = len(prob_list)
    dp = [[0]*(k+1) for i in range(n+1)]   #dp[i][j] 抛i次出现j次正面朝上的概率
    dp[0][0] = 1
    for i in range(1, n+1):
        dp[i][0] = (1-prob_list[i-1])*dp[i-1][0]
    for i in range(1, n+1):
        for j in range(k+1):
            dp[i][j] = dp[i-1][j-1]*prob_list[i-1] + dp[i-1][j]*(1-prob_list[i-1])
    return dp[n][k]
    
coin flip

 

 G.Trie(字典树)

 

 Word search II

#coding:utf-8

"""
lintcode 132. Word Search II
Description

Given a matrix of lower alphabets and a dictionary. Find all words in the dictionary that can be found in the matrix. A word can start from any position in the matrix and go left/right/up/down to the adjacent position.
 One character only be used once in one word. No same word in dictionary

Example 1:

    Input:["doaf","agai","dcan"],["dog","dad","dgdg","can","again"]
    Output:["again","can","dad","dog"]
    Explanation:
      d o a f
      a g a i
      d c a n
    search in Matrix,so return ["again","can","dad","dog"].

Example 2:

    Input:["a"],["b"]
    Output:[]
    Explanation:
     a
    search in Matrix,return [].

Challenge

Using trie to implement your algorithm.

"""

#参考:https://www.jiuzhang.com/solutions/word-search-ii/#tag-highlight-lang-python

#构建trie tree

class TrieNode(object):
    
    def __init__(self):
        self.children={}
        self.is_word=False
        self.word=None
        
class TrieTree(object):
    
    def __init__(self):
        self.root = TrieNode()

    def add(self,word):
        node =self.root
        for c in word:
            if c not in node.children:
                node.children[c]=TrieNode()
            node = node.children[c]
        node.is_word=True
        node.word=word
    
    def search(self,word):
        node = self.root
        for c in word:
            if c not in node.children:
                return None
            node = node.children[c]
        return node
    
DIRECTIONS=[(0,1),(0,-1),(-1,0),(1,0)]
    
class Solution:
    """
    @param board: A list of lists of character
    @param words: A list of string
    @return: A list of string
    """
    def wordSearchII(self, board, words):
        # write your code here
        if len(words)==0 or len(board)==0:
            return []
        trie = TrieTree()
        for word in words:
            trie.add(word)
        
        ret = []
        root = trie.root
        for i in range(len(board)):
            for j in range(len(board[i])):
                self.search(board,i,j,root,ret,set([(i,j)]))
        return ret
                
    def search(self,board,i,j,node,ret,visited):
        node = node.children.get(board[i][j],None)
        if node==None:
            return 
        if node.is_word and node.word not in ret:
            ret.append(node.word)
        for d in DIRECTIONS:
            x,y = i+d[0],j+d[1]
            if self.in_board(x,y,board):
                if (x,y) not in visited:
                    visited.add((x,y))
                    self.search(board,x,y,node,ret,visited)
                    visited.remove((x,y))
    
    def in_board(self,x,y,board):
        if 0<= x <len(board) and 0<=y<len(board[x]):
            return True


#用图的方法,如何避免一个字母不被重复利用?    
# class Solution:
    # """
    # @param board: A list of lists of character
    # @param words: A list of string
    # @return: A list of string
    # """
    # def wordSearchII(self, board, words):
        # #write your code here

        # if len(words)==0 or len(board)==0:
            # return []

        # #建立图
        # graph = dict()
        # length1=len(board)
        # for i in range(length1):
            # length2 = len(board[i])
            # for j in range(length2):
                # if board[i][j] not in graph:
                    # graph[board[i][j]]=set()
                # if i>0 and j<len(board[i-1]):
                    # graph[board[i][j]].add(board[i-1][j])
                # if i<length1-1 and j<len(board[i+1]):
                    # graph[board[i][j]].add(board[i+1][j])
                # if j>0:
                    # graph[board[i][j]].add(board[i][j-1])
                # if j<length2-1:
                    # graph[board[i][j]].add(board[i][j+1])
        # ret=[]
        # for word in words: 
            # if word[0] in graph:
                # self.dfs(graph,word,1,ret)
        # return ret
        
    # def dfs(self,graph,word,index,ret):
            
        # if index==len(word):
            # ret.append(word)
            # return
            
        # char = word[index]
        # if char not in graph[word[index-1]]:
            # return
        # self.dfs(graph,word,index+1,ret)
    
        

            
if __name__=="__main__":
    s = Solution()
    print(s.wordSearchII(["doaf","agai","dcan"],["dog","dad","dgdg","can","again"]))
    print(s.wordSearchII(["doaf","agai","can"],["dog","dad","dgdg","can","again"]))
    print(s.wordSearchII(["a"],["b"]))
    print(s.wordSearchII(["abce","sfcs","adee"],["see","se"]))
    print(s.wordSearchII(["b","a","b","b","a"],["babbab","b","a","ba"]))
    print(s.wordSearchII(["abce","sfcs","adee"],["abcb","ninechapter","lintcode"]))
    print(s.wordSearchII(["abce","sfcs","adee"],["as","ab","cf","da","ee","e","adee","eeda"]))
                
                    
            
        
        
        
Word Search II

 

#coding:utf-8

"""
题目描述:
What you are given is a sentence like:
“I am happy and sad”
Please forget about how insane it is, just focusing on the following questions.
And then some substitutes of some words are provided as well:[["happy", "glad"], ["glad", "good"], ["sad", "sorrow"]]
which means happy can be replaced by glad while glad can continuously substituted by good and so on.
Now, please write out all possible sentences with all substitutes. 
For example, by giving this specific case, your output should be like:
I am happy and sad
I am happy and sorrow
I am glad and sad
I am glad and sorrow
I am good and sad
I am good and sorrow
"""


import copy

def make_sentence(ori_sentence, substitutes):
    """
    ori_sentence: string, "I am happy and sad"
    substitutes: list of list, [["happy", "glad"], ["glad", "good"], ["sad", "sorrow"]]
    return: list of string
    """
    if not ori_sentence or not substitutes or not len(substitutes[0]):
        print("Empty ori_sentence or substitutes")
        return 
    words = ori_sentence.split(" ")
    sub = {k:v for [k,v] in substitutes}
    id_words = []
    for word in words:
        temp = []
        temp.append(word)
        if word in sub.keys():
            while word in sub.keys():
                temp.append(sub[word])
                word = sub[word]
        id_words.append(temp)
    ret = []
    helper(id_words, 0, ret)
    return [" ".join(item) for item in ret]

def helper(id_words, depth, ret, sentence=[]):
    if len(sentence)==len(id_words):
        ret.append(copy.deepcopy(sentence))
    else:
        for word in id_words[depth]:
            sentence.append(word)
            helper(id_words, depth+1, ret, sentence)
            sentence.pop()
            
if __name__ == "__main__":
    ori_sentence = "I am happy and sad"
    substitutes = [["happy", "glad"], ["glad", "good"], ["sad", "sorrow"]]
    sentences = make_sentence(ori_sentence, substitutes)
    for st in sentences:
        print(st)
    
    
make sentence

 

posted @ 2024-09-21 14:32  silence_cho  阅读(31)  评论(0编辑  收藏  举报