2015年7月26日星期日

Remove Duplicates from Sorted List II leetcode

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.
因为表头可能被删除, 创建一个dummy node, 令dummynode.next = head, return dummy.next
时间O(n) 空间O(1)
 
public class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode cur = head;
        ListNode pre = dummy;
        while (cur != null && cur.next != null) {
            if (cur.val == cur.next.val) {
                int val = cur.val;
                while (cur != null && cur.val == val) {
                    cur = cur.next;
                }
                pre.next = cur;
            } else {
                pre = pre.next;
                cur = cur.next;
            }
        }
        return dummy.next;
    }
}
public class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null || head.next == null){
            return head;
        }
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        head = dummy;
        while (head.next != null && head.next.next != null){
            if (head.next.val == head.next.next.val){
                int val = head.next.val;
                while (head.next != null && head.next.val == val){
                    head.next = head.next.next;
                }
            } else {//注意一定要在else语句里head往下传递 否则会溢出
                head = head.next;
            }
        }
        return dummy.next;
    }
}

2015年7月25日星期六

链表总结

链表的基本形式是:1 -> 2 -> 3 -> null,反转需要变为 3 -> 2 -> 1 -> null。

  • 访问某个节点 curt.next 时,要检验 curt 是否为 null。 
  • 要把反转后的最后一个节点(即反转前的第一个节点)指向 null。

public ListNode reverse(ListNode head) {
    ListNode prev = null;
    while (head != null) {
        ListNode next = head.next;
        head.next = prev;
        prev = head;
        head = next;
    }
    return prev;
}




1 -> 2 -> 3 -> 4 -> 5 -> 6 -> null变为 1 -> 5 -> 4 -> 3 -> 2 -> 6 -> null
翻转m--n, 不仅要把m-n转好, preMnode. next 要指向n, m.next 要指向postNnode

public class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        if (m > n || head == null){
            return head;
        }
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        head = dummy;
        for (int i = 1; i < m; i++){
            head = head.next;
        }
        ListNode preM = head;
        ListNode mNode = head.next;
        ListNode nNode = mNode;
        ListNode postN = mNode.next;
        for (int i = m; i < n; i++){
            ListNode tem = postN.next;
            postN.next = nNode;
            nNode = postN;
            postN = tem;
        }
        preM.next = nNode;
        mNode.next = postN;
        return dummy.next;
    }
}

删除链表中的某个节点 

删除链表中的某个节点一定需要知道这个点的前继节点,所以需要一直有指针指向前继节点。
然后只需要把 prev -> next = prev -> next -> next 即可。但是由于链表表头可能在这个过程中产生变化,导致我们需要一些特别的技巧去处理这种情况。就是下面提到的 Dummy Node。

找中点

        ListNode fast = head;
        ListNode slow = head;
        while (fast!= null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }


链表指针的鲁棒性

综合上面讨论的两种基本操作,链表操作时的鲁棒性问题主要包含两个情况:
  • 当访问链表中某个节点 curt.next 时,一定要先判断 curt 是否为 null。
  • 全部操作结束后,判断是否有环;若有环,则置其中一端为 null。

Dummy Node


Dummy node 是一个虚拟节点,也可以认为是标杆节点。Dummy node 就是在链表表头 head 前加一个节点指向 head,即 dummy -> head。Dummy node 的使用多针对单链表没有前向指针的问题,保证链表的 head 不会在删除操作中丢失。除此之外,还有一种用法比较少见,就是使用 dummy node 来进行head的删除操作,比如 Remove Duplicates From Sorted List II,一般的方法current = current.next 是无法删除 head 元素的,所以这个时候如果有一个dummy node在head的前面。
所以,当链表的 head 有可能变化(被修改或者被删除)时,使用 dummy node 可以很好的简化代码,最终返回 dummy.next 即新的链表。

快慢指针

快慢指针也是一个可以用于很多问题的技巧。所谓快慢指针中的快慢指的是指针向前移动的步长,每次移动的步长较大即为快,步长较小即为慢,常用的快慢指针一般是在单链表中让快指针每次向前移动2,慢指针则每次向前移动1。快慢两个指针都从链表头开始遍历,于是快指针到达链表末尾的时候慢指针刚好到达中间位置,于是可以得到中间元素的值。快慢指针在链表相关问题中主要有两个应用:
  • 快速找出未知长度单链表的中间节点 设置两个指针 *fast*slow 都指向单链表的头节点,其中*fast的移动速度是*slow的2倍,当*fast指向末尾节点的时候,slow正好就在中间了。
  • 判断单链表是否有环 利用快慢指针的原理,同样设置两个指针 *fast*slow 都指向单链表的头节点,其中 *fast的移动速度是*slow的2倍。如果 *fast = NULL,说明该单链表 以 NULL结尾,不是循环链表;如果 *fast = *slow,则快指针追上慢指针,说明该链表是循环链表。


Remove Duplicates from Sorted List

Remove Duplicates from Sorted ListII



Reorder List

Merge k Sorted Lists

Remove Nth Node From End of List

List Cycle

Linked List Cycle II


Reverse Nodes in k-Group

Rotate List

Insertion Sort List

2015年7月23日星期四

binary search 总结

二分法比较简单, 时间复杂度为O(log n)
mid = right + (left - right) / 2 防止left right 都大时候溢出
两种二分法
1. start <= end 每次start = mid + 1 或者 end = mid - 1
2. start + 1 < end 每次 start = mid 或者 end = mid

正常情况下用1的方法, 但是如果mid+1 或者mid-1 可能会错过target的话(mid 为target) 例如Find Minimum in Rotated Sorted Array 用方法2

Search for a Range

Search Insert Position

Sqrt(x)

Search in Rotated Sorted Array

前边的题只需要mid 跟target比较 而这两道题则还需要跟左右边界比较 所以要注意跟边界相等的情况下不仅会出现 > < 还有>= <=


Find Minimum in Rotated Sorted Array
与之前不同的是如果这道题每次 Amid < A[right] -->mid - 1 = right 的话那么 可能会出现如果此时mid是最小值 但是右边界确实最大值 为了防止这种情况 每次left right 都取 mid 而不是mid +-1 但是这么取得话就不能用left <= right 了 否则会无限循环 所以这里用left + 1 < right
Find Minimum in Rotated Sorted Array II

Search a 2D Matrix

2015年7月20日星期一

Unique Paths II leetcode

Follow up for "Unique Paths":
Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and empty space is marked as 1 and 0 respectively in the grid.
For example,
There is one obstacle in the middle of a 3x3 grid as illustrated below.
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
The total number of unique paths is 2.
在第i个位置上设置一个障碍物后,说明位置i到最后一个格子这些路都没法走 为0
所以说明,在初始条件时,如果一旦遇到障碍物,障碍物后面所有格子的走法都是0
再看求解过程,当然按照上一题的分析dp[i][j] = dp[i-1][j] + dp[i][j-1] 的递推式依然成立.碰到了障碍物,那么这时的到这里的走法应该设为0,因为机器人只能向下走或者向右走,所以到这个点就无法通过。
时间O(m*n) 空间O(m*n) 
public class Solution {
public class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        if (obstacleGrid == null || obstacleGrid.length == 0 || obstacleGrid[0].length == 0) {
            return 0;
        }
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int [][] sum = new int [m][n];
        for (int i = 0; i < m; i++) {
            if (obstacleGrid[i][0] != 1) {
                sum[i][0] = 1;
            } else {
                break;//后面所有的都无法到达所以break
            }
        }
        for (int j = 0; j < n; j++) {
            if (obstacleGrid[0][j] != 1) {
                sum[0][j] = 1;
            } else {
                break;
            }
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (obstacleGrid[i][j] != 1) {
                    sum[i][j] = sum[i-1][j] + sum[i][j-1];
                } else {
                    sum[i][j] = 0;
                }
            }
        }
        return sum[m-1][n-1];
        
    }
}

2015年7月16日星期四

动态规划总结

When to use DP?


  • Input cannot sort
  • Find minimum/maximum result
  • Check the feasibility 找可行性
  • Count all possible solutions 列出所有解


(1) 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
(2) 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
(3)有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势

4 Types of DP

  • 1. Matrix DP (10%)
  • 2. Sequence (40%)
  • 3. Two Sequences DP (40%)*
  • 4. Backpack (10%)

通用解法:

1.  状 态 State

2. 方程 Function
状态之间的联系,怎么通过小的状态,来算大的状态

3. 初始化 Intialization
最极限的小状态是什么, 起点

4. 答案 Answer
最大的那个状态是什么,终点

Matrix DP


  • state: f[x][y] 表示我从起点走到 坐 标x,y……
  • function: 研究走到xy 这个点之前的一步是从哪里走的
  • intialize: 起点
  • answer: 终点

Sequence Dp

  • state: f[i]表示“ 前i”个位置/数字/字母,(以第i个为)...
  • function: f[i] = f[j] … j 是i之前的一个位置
  • intialize: f[0]..
  • answer: f[n-1]..


Two Sequences Dp


  • state: f[i][j]代表了第一个sequence的前i个数字/字符 配上第二个sequence的前j个...
  • function: f[i][j] = 研究第i个和第j个的匹配关系
  • intialize: f[i][0] 和 f[0][i](二维数组都要初始化第0行和第0列)
  • answer: f[s1.length()][s2.length()]

1. sequences
Climbing Stairs

Decode Ways

Unique Binary Search Trees

Maximum Subarray


Word Break

Palindrome Partitioning II



2. Matrix
Triangle

Unique Paths I

Unique Paths II

Minimum Path Sum

3. two sequences

Edit Distance

Distinct Subsequences

Interleaving String

Scramble String(3 sequences)