LeetCode Weekly Contest 8 第八周周赛

415. Add Strings

Given two non-negative numbers num1 and num2 represented as string, return the sum of num1 and num2.

就是模拟加法,将两个字符串表示的数字相加。其中字符串的长度均不超过5100,字符串中只有0-9,即不可能有负数的情况。

解法很简单,就是按照小学时候教的加法运算来做就行了。

func addStrings(num1 string, num2 string) string {
    l1,l2 := len(num1),len(num2)
    if l1 == 0{
        return num2
    }
    if l2 == 0{
        return num1
    }
    ret := ""
    add :=0
    for l1,l2 = l1-1,l2-1 ;l1>=0 && l2 >=0;l1,l2 = l1-1,l2-1{
        t := int(int(num1[l1]) - int('0') + int(num2[l2]) - int('0') +add)
        if t >=10{
            t -= 10
            add = 1
        }else{
            add = 0
        }
        ret = string(t+'0') + ret
    }
    if l1 < 0{
        l1, num1 = l2,num2
    }
    for ;l1>=0;l1--{
        t := int(int(num1[l1]) - int('0')  + add)
                if t >=10{
            t -= 10
            add = 1
        }else{
            add = 0
        }
        ret = string(t+'0') + ret
    }
    if add == 1{
        ret = "1" + ret
    }
    return ret;
}

416. Partition Equal Subset Sum

Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
给定一个非空只含有正整数的数组,查找数组能不能分成两个和相等的部分。
显然,如果能被分成两个和相等的部分,那么这个数组的和一定要是偶数,而且被分成的两个部分一定是数组的和sum的一半。
可以用动态规划做,dp[i][j]表示的是集合num[0]-num[j-1]中,存在一个子集的和为i
那么,就有dp[sum/2][len(num]中如果存在一个子集,和为sum/2,就说明这个集合满足题意。
动态规划的状态转移方程为:

            dp[i][j] = dp[i][j-1]//如果集合0~j-1存在,则集合0~j中也一定存在。
            if i>=nums[j-1]{
                dp[i][j] = dp[i][j] || dp[i-nums[j-1]][j-1]//集合0~j-2中如果有和为j-num[j-1]的子集,那么再加上数字num[j-1],就能组成和为j的集合。
            }

下面是AC的Golang代码。

func canPartition(nums []int) bool {
    sum := 0
    for i:=0;i<len(nums);i++{
        sum += nums[i]
    }
    if sum%2 == 1{
        return false
    }
    dp := make([][]bool,sum/2+1)
    for i:=0;i<len(dp);i++{
        dp[i] = make([]bool,len(nums)+1)
    }
    for i:=0;i<=len(nums);i++{
        dp[0][i] = true
    }
    for i := 1;i<=sum/2;i++{
        for j:=1;j<=len(nums);j++{
            dp[i][j] = dp[i][j-1]
            if i>=nums[j-1]{
                dp[i][j] = dp[i][j] || dp[i-nums[j-1]][j-1]
            }
        }
    }
    return dp[sum/2][len(nums)]
}

417. Pacific Atlantic Water Flow

Given an m x n matrix of non-negative integers representing the height of each unit cell in a continent, the “Pacific ocean” touches the left and top edges of the matrix and the “Atlantic ocean” touches the right and bottom edges.

Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower.

Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean.

Example:

Given the following 5x5 matrix:

  Pacific ~   ~   ~   ~   ~ 
       ~  1   2   2   3  (5) *
       ~  3   2   3  (4) (4) *
       ~  2   4  (5)  3   1  *
       ~ (6) (7)  1   4   5  *
       ~ (5)  1   1   2   4  *
          *   *   *   *   * Atlantic

Return:

[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions with parentheses in above matrix).

给定一个2维数组,数组中的每一个坐标的数值代表这个点的高度。如果这个坐标的数不小于相邻坐标的点数值(东西南北四个点),那么这个坐标上的水就能流到相邻的坐标。问题是求出这个2维数组中所有的/水能够流到(西/北)和(东/南)两组边的点的坐标。示例中打上括号的点就是所求。
思路:
如果一个点,上面的水可以流到一个边,那么如果有一个点上的水,能够流到这个点上,那么它一定也可以流到这个边上。
所以问题就变成了,已知一个点上的水可以流到某个边,求出所有上面的水能够到达这个点的其它点。显然可以用dfs来做。
AC代码如下:

var walkx = [4]int{1, -1, 0, 0}
var walky = [4]int{0, 0, 1, -1}

func help(m, f [][]int, x, y int, flag int) {
    f[x][y] |= flag
    for i := 0; i < 4; i++ {
        _x, _y := x+walkx[i], y+walky[i]
        if _x >= 0 && _x < len(m) && _y >= 0 && _y < len(m[0]) && m[x][y] <= m[_x][_y] && f[_x][_y]&flag == 0 {
            help(m, f, _x, _y, flag)
        }
    }
}

func pacificAtlantic(matrix [][]int) [][]int {
    ret := [][]int{}
    if len(matrix) == 0 || len(matrix[0]) == 0 {
        return ret
    }
    m, n := len(matrix), len(matrix[0])
    flag := make([][]int, m)
    for i := 0; i < m; i++ {
        flag[i] = make([]int, n)
    }
    for i := 0; i < m; i++ {
        flag[i][0], flag[i][n-1] = flag[i][0]|1, flag[i][n-1]|2
    }
    for i := 0; i < n; i++ {
        flag[0][i], flag[m-1][i] = flag[0][i]|1, flag[m-1][i]|2
    }
    for i := 0; i < m; i++ {
        help(matrix, flag, i, 0, 1)
        help(matrix, flag, i, n-1, 2)
    }
    for i := 0; i < n; i++ {
        help(matrix, flag, 0, i, 1)
        help(matrix, flag, m-1, i, 2)
    }
    for i := 0; i < m; i++ {
        for j := 0; j < n; j++ {
            if flag[i][j] == 3 {
                ret = append(ret, []int{i, j})
            }
        }
    }
    return ret

}

418. Sentence Screen Fitting

Given a rows x cols screen and a sentence represented by a list of words, find how many times the given sentence can be fitted on the screen.

Note:

  1. A word cannot be split into two lines.
  2. The order of words in the sentence must remain unchanged.
  3. Two consecutive words in a line must be separated by a single space.
  4. Total words in the sentence won’t exceed 100.
  5. Length of each word won’t exceed 10.
  6. 1 ≤ rows, cols ≤ 20,000.

Example 1:

Input:
rows = 2, cols = 8, sentence = ["hello", "world"]

Output: 
1

Explanation:
hello---
world---

The character '-' signifies an empty space on the screen.

Example 2:

Input:
rows = 3, cols = 6, sentence = ["a", "bcd", "e"]

Output: 
2

Explanation:
a-bcd- 
e-a---
bcd-e-

The character '-' signifies an empty space on the screen.

Example 3:

Input:
rows = 4, cols = 5, sentence = ["I", "had", "apple", "pie"]

Output: 
1

Explanation:
I-had
apple
pie-I
had--

The character '-' signifies an empty space on the screen.

给定一堆字符串数组sentence,以及一个行和列(可以看成一个二维数组)。按字符串顺序填充这个二维数组,问填充完这个数组需要重复多少次sentence。在同一行,每个单词之间都要有一个空格。

这道题很思路很简单。其实就只要依次把字符串的长度往行上加,然后在填完一行之后换行即可。
按照如上思路做会在["a"],20000,20000["a","b","e"],20000,20000这种case中挂掉。
所以需要进行优化。
有两个地方可以优化。
首先是如果我们填充完一行时,正好这个时候我们也完成了一次重复。
比如这个例子。

Input:
rows = 6, cols = 5, sentence = ["I", "had", "apple"]


Explanation:
I-had
apple
I-had
apple
I-had
apple

在第二行的时候,我们第一次碰到了这种情况。此时观察最后的匹配结果,可以发现第3,4行,第5,6行实际上是第1,2行的重复,所以如果我们碰到了这种情况,直接就可以跳过中间重复的循环过程。

第二个优化是在行内匹配的时候,比如下面这个case:

Input:
rows = 10, cols = 2000, sentence = ["a", "b", "c"]


Explanation:
a-b-c-a-b-c-a-b-c-a-b-c...

可以发现,如果在一行内就能匹配完全部的sentence,那么我们就可以直接跳过中间重复的循环,直接到达这一行的末尾。不过这个优化在代码中没有体现,因为只用了第一种优化就AC了。
Golang AC 代码:

func wordsTyping(sentence []string, rows int, cols int) int {
    l := make([]int, len(sentence))
    for i := 0; i < len(l); i++ {
        l[i] = len(sentence[i])
    }
    rep := 0
    idx := 0
    left := cols
    //s := 0
    //repeat_start := 0
    for r := 0; r < rows; {

        if left == cols {
            if l[idx] > cols {
                return 0
            }
            left -= l[idx]
            idx++
        } else {
            if left < l[idx]+1 {
                left = cols
                //idx ++
                r++

            } else {
                if l[idx] > cols {
                    return 0
                }
                left -= l[idx] + 1
                idx++
            }
        }
        if idx == len(l) {
            rep++
            idx = 0
            if left < l[0]+1 { //发现可以优化跳步,直接跳过中间重复的片段。
                r++
                tmp := rows / r
                if tmp*r == rows {
                    return tmp * rep
                } else {
                    rep *= tmp
                    r = tmp * r
                    r--
                }
            }
        }
    }
    return rep

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值