LeetCode 160, 139, 41 题解

LeetCode 160, 139, 41 题解

如下的表达纯属我的理解,若是有不对,欢迎指出 : )。node

题解

(LeetCode 160)Intersection of Two Linked Lists

题目:

Write a program to find the node at which the intersection of two singly linked lists begins.数组

For example, the following two linked lists:spa

A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3

begin to intersect at node c1.指针

Notes:code

  • If the two linked lists have no intersection at all, return null.内存

  • The linked lists must retain their original structure after the function returns.leetcode

  • You may assume there are no cycles anywhere in the entire linked structure.字符串

  • Your code should preferably run in O(n) time and use only O(1) memory.get

大意就是给了两个链表,而后这两个链表的后面有一个段公共部分,让你找到这段公共部分的开始节点。数据保证链表里面没有环。若是两个链表没有公共部分,就返回空。要求在寻找的过程当中,必须保持两个链表的原始结构,同时时间和空间复杂度要求为 O(n) 和 O(1)。同步

题解

其实在不少状况下,实现 O(n) 复杂度的方式,就是多走几遍,只要这个几是常数就能够了。

在这道题里面,因为链表都是单链表,因此只能一直日后走,不能往前走。同时在一个节点上的时候,不能知道这个链表后面的状况(好比说元素的个数)。

对于像这样的链表(或者说是节点指针结构)找公共节点的题,要找公共节点,比较直接能想到的是:若是两个指针自己是上下对齐的(就是说距离公共节点的距离),只要两个指针一块儿往前走,就确定会走到同一个节点。

但是如今两个指针是不对齐的,怎么办呢?就让他对齐呗。

按照前面说的多走几遍的套路,看看走一次能获得什么:链表的长度。观察链表:后边的公共部分的长度是相同的,因此长度的差别就在前面,那咱们只要把两个链表的长度差 distance 算出来,让指向长链表的指针提早走 distance 步,就能够了同步走了。

function get_insersection_node(headA, headB)
    distance <- get_length_diff(headA, headB)
    longer_pointer <- get_longer_link_head(headA, headB)
    shorter_pointer <- get_short_link_head(headA, headB)
    move_pointer(longer_poiner, distance)
    
    while (longer_pointer != nil) and (shorter_pointer != nil)
        if (longer_pointer = short_pointer) then
            return longer_pointer
        longer_pointer <- longer_pointer.next
        shorter_pointer <- shorter_pointer.next
        
    // 跑到这里说明两个链表并无公共部分
    return nil

相似的题

给定一个二叉树,每一个节点都有指向他老爸的指针。再给任意两个节点,找到他们的最年轻的公共祖先。

这个题,其实能够用和同上面的题相同的思路解决 : )

(LeetCode 139) Word Break

题目

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words.

For example, given
s = "leetcode",
dict = ["leet", "code"].

Return true because "leetcode" can be segmented as "leet code".

大意就是给定一个字符串和一个单词列表,判断这个字符串是否是能够彻底由单词列表的单词组成。题目保证单词列表里面不会有重复的单词

题解

定义 s[m..n] (m <= n)表示 字符串从第 m 个到第 n 个字符组成的子串。

设 s 的长度为n

观察这个问题,其实这个问题是能够拆分红不少彻底相同的字问题的。对于这个问题的定义能够表述成:判断 s[1..n] 能不能彻底由单词列表里面的单词组成。

那么,他的子问题(规模较小的问题) 就是: s[1..1], s[1..2], s[1..3], … s[1..n - 1] 能不能彻底由单词列表里面的单词组成。

假设存在一个j(1 <= j < n),使得 s[1..j] 是能够彻底由单词列表的单词组成的,同时 s[j + 1 .. n] 这个单词又在字典列表里面,那么就说明 s[1..n] 是能够彻底由单词列表里面的单词构成的。

也就是说,要解决 s[1..n] 的问题,咱们解决了 s[1..1], s[1..2], s[1..3], … s[1..n-1] 这些子问题(由于若是不所有解决的话,就不知道是否存在这么一个 j )。反过来讲,只要解决 s[1..1], s[1..2], s[1..3], … s[1..n-1] 这些子问题,咱们就能解决 s[1..n] 的问题。

在解决这个问题的过程当中,s[1..n] 问题所处的阶段就叫当前阶段,对于当前阶段而言,s[1..1], s[1..2], s[1..3], … s[1..n-1] 问题所处的阶段就是上一阶段

s[1..n] 可否彻底由单词列表里的单词组成,就是当前阶段的状态,s[1..1], s[1..2], s[1..3], … s[1..n-1]可否彻底由单词列表里面的单词组成,就是上一阶段的状态

好,如今来观察一下上面的分析,就能发现 对于一个 s[1..n] 问题,有可能,从上一阶段的几个状态都能到达当前的状态。也就是说:单词的选择方式不必定是惟一的。可是,在解决 s[1..n] 的时候,并不须要关心 s[1..1],s[1..2],..,s[1..n -1] 问题的解是怎么来的。这就是无后效性

当一个判断性的问题,具备这种子问题性质和无后效性的性质,就能够考虑采用动态规划的方式去作。

状态咱们已经定义好了,那么用状态变量 is_beakable[i] 来表示 "s[1..n] 可否彻底由单词列表里的单词组成" 这个状态。true 表示能够,false 表示不能够。

从各个 s[1..j] 到 s[1..n] 就称为状态转移,这里的状态转移链接了当前阶段和上一阶段。咱们能够考虑用状态转移方程来描述(is_breakable[i] 默认值为 false):

is_breakable[i] = is_breakable[i] Or ((is_breakable[j] = true) And (s[j + 1..n] in dict))

就这样,咱们一直算出 is_breakable[n] 就算是将问题求解完了。

function word_break(s, dict)
    is_breakable[0] = false;
    for i <- 1 to n do 
        is_breakable[i] = false;
        for j <- 0 to n do
            is_breakable[i] = is_breakable[i] or ((is_breakable[j] = true) and (s[j + 1..n] in dict))
    return is_breakable[n]

(LeetCode 41) First Missing Positive

题目

Given an unsorted integer array, find the first missing positive integer.

For example,
Given [1,2,0] return 3,
and [3,4,-1,1] return 2.

Your algorithm should run in O(n) time and uses constant space.

大意就是,给定一个没有排过序的数组,里面的数有负有正。正整数序列是:1, 2, 3,… 找到第一个丢失的正整数。要求时间复杂度和空间复杂度是O(n)和O(1)。

题解

这个题,并无不改变原数组就能在O(n)的空间效率内实现的方法,因此只能考虑改变原有的内存。

观察这个题,知道:

  1. 目标数确定是个大于0的数。

  2. 目标数的大小,确定会比数组的长度小。

从这两个信息,咱们能够获得:

  1. 可以用正负号来作标记

  2. 能用经过数组的下标来进行标记

  3. 数组里面,小于等于0的和大于数组长度的数都是不重要的数,大于0和小于等于数组长度的数都是重要的数

那么作法就出来了:

  1. 走一遍,把数组里面小于等于零的数和大于数组长度的数都设置成一个比数组长度要大的数

  2. 再走一遍,把数组以重要的数为下标的元素都设置成负的

  3. 最后走一遍,碰到数组里面第一个非负的数,他的下标就是咱们的答案

function fisrt_missing_positive(nums, nums_size)
    for i <- 1 to nums_size do
        if (nums[i] <= 0) or (nums[i] > nums_size) then
            nums[i] = nums_size + 1
        
    for i <- 1 to nums_size do 
        if (nums_size + 1 != nums[i]) then
            index = abs(nums[i])
            nums[index] = -1 * abs(nums[index]) 
            
    for i <- 1 to nums_size do 
        if (nums[i] < 0) then
            answer = i
            break
            
    return answer
相关文章
相关标签/搜索