Leet Code 笔记

Leet Code 笔记

53. Maximum Subarray 最大子段和

2019.07.22
leetcode 53

动态规划

原数组 n u m [   ] num[\space] num[ ]
记录数组 s u m [ i ] sum[i] sum[i]保存的是原数组以位置 i i i结尾在 n u m [ 0... i ] num[0...i] num[0...i]区间内的最大子段和
初始值 s u m [ 0 ] sum[0] sum[0]= n u m [ 0 ] num[0] num[0]
可以写出如下递推公式:

s u m [ i ] = { s u m [ i − 1 ] + n u m [ i ] if  s u m [ i − 1 ] > 0 n u m [ i ] else sum[i] = \begin{cases} sum[i-1] + num[i] &\text{if} \space sum[i-1]>0\\ num[i] &\text{else} \end{cases} sum[i]={sum[i1]+num[i]num[i]if sum[i1]>0else
因为只需要求得最大的结果,所以可以用一个变量 r e s res res来代替 s u m [ i − 1 ] sum[i-1] sum[i1]的功能,从前到后扫描一次数组,并用一个变量 m a x v maxv maxv记录最大的 r e s res res返回.

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        res = nums[0]
        maxv = nums[0]
        for i in range(1, len(nums)):
            res = res + nums[i] if res > 0 else nums[i]
            if maxv < res:
                maxv = res
        return maxv

62. Unique Paths 不同的路径

2019.07.22
leetcode 62

组合数学

这个问题其实可以转化成组合数学。因为每次只能向右或向下走一步,最多能走的是向右 m − 1 m-1 m1步,向下 n − 1 n-1 n1步。假设 n &lt; m n&lt;m n<m,其实是在 m − 1 m-1 m1步的间隔位置包括开始和结尾,插入 n − 1 n-1 n1步,并且可以连续插入在同一个间隔。将向右移视为 1 1 1,向下移视为 0 0 0,问题转化为在 ( m + n − 2 ) (m+n-2) m+n2个位置上选择 ( m − 1 ) (m-1) m1个放置 1 1 1,其余放置 0 0 0,可以直接用组合公式求解。

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        return self.cfun(m+n - 2,n - 1)
 
    def cfun(self,a,b):
        min = a-b if a-b < b else b
        res = 1
        for i in range(min):
            res = res *  (a - i) // (i + 1)
        return res

动态规划


160. Intersection of Two Linked Lists 两个链表的交汇点

2019.09.06
leetcode 160
在这里插入图片描述

双指针法

  1. 可以遍历一遍两个链表,然后让长的链表先出发,到达他们长度相同的位置后,同时出发,当两个指针相等时退出循环
  2. 更巧妙地方法是,让两个指针同时出发,当其中一个走到链表尾端,此时它等于 n u l l null null,将它置为另一个链表的开头,继续前进,直到两个指针相等时退出循环。具体证明:
    A A A链表长度为 l e n A lenA lenA B B B链表长度为 l e n B lenB lenB
    当其中一个指针走到结尾,将它置为另一个链表的开始,这样他会多走另一个链表的长度,
    len A ′ = len A + len B \text{len}A&#x27; = \text{len}A + \text{len}B lenA=lenA+lenB
    len B ′ = len B + len A \text{len}B&#x27; = \text{len}B + \text{len}A lenB=lenB+lenA
    len A ′ = len B ′ \text{len}A&#x27; = \text{len}B&#x27; lenA=lenB
    他们走的总长度相同,所以总会在交汇点处相遇。另外,当 c = 0 c=0 c=0时,他们都为 n u l l null null,此时跳出循环并返回 n u l l null null
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //boundary check
        if(headA == null || headB == null) return null;
    
        ListNode a = headA;
        ListNode b = headB;
    
        //if a & b have different len, then we will stop the loop after second iteration
        while( a != b){
    	//for the end of first iteration, we just reset the pointer to the head of another linkedlist
            a = a == null? headB : a.next;
            b = b == null? headA : b.next;    
        }
    
        return a;
    }
}

167. Two Sum II 两数之和2

leetcode 167

双指针法

因为是排序好的数组,头尾各一个指针向中间遍历,如果两数之和等于目标值,跳出循环,如果大于则移动尾指针,使和变小,否则移动头指针,使和变大,直到两个指针相遇。

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int[] ans = new int[2];
        int left = 0;
        int right = numbers.length-1;
        while(left != right){
            int sum = numbers[left]   + numbers[right];
            if(sum == target){
                ans[0] = left + 1;
                ans[1]= right + 1;
                break;
            }
            else if(sum > target){
                right--;
            }
            else{
                left++;
            }
        }
        return ans;
    }
}

241 加括号的不同结果

leetcode 241
在这里插入图片描述

分治算法

原问题可以从运算符号位置拆分为左右各一个子问题,运用递归不断求解子问题,组合成原问题。加速的方法使用备忘录,记录之前计算过的子问题。

public class Solution {
    private HashMap<String, List<Integer>> hashmap = new HashMap<String, List<Integer>>();
    public List<Integer> diffWaysToCompute(String input) {
        if(hashmap.containsKey(input))
            return hashmap.get(input);
        List<Integer> res = new ArrayList<Integer>();
        for(int i = 0; i < input.length(); i++){
            char ch = input.charAt(i);
            if(ch == '*' || ch == '+' || ch == '-')
                for(int l: diffWaysToCompute(input.substring(0, i)))
                    for(int r: diffWaysToCompute(input.substring(i+1)))
                        switch(ch){
                            case '*': res.add(l * r);
                                break;
                            case '+': res.add(l+r);
                                break;
                            case '-': res.add(l-r);
                                break;
                            default: break;
                        }
        }
        if(res.size()==0)
            res.add(Integer.valueOf(input));
        hashmap.put(input, res);
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值