LeetCode Biweekly Competition 104 (2023/05/13) Dynamic planning of flow, structured thinking of hard work

This article has included AndroidFamily , technical and workplace issues, please pay attention to the public account [Peng Xurui] to ask questions.


T1. Number of elderly people (Easy)

  • Tags: simulation, counting

T2. Sum in Matrix (Medium)

  • Tags: simulation, sorting

T3. Maximum or value (Medium)

  • Tags: dynamic programming, suffix decomposition, greedy

T4. Hero's Strength (Hard)

  • Tags: sorting, greedy, dynamic programming, mathematics


T1. Number of elderly people (Easy)

https://leetcode.cn/problems/number-of-senior-citizens/

Simple simulation questions, just intercept the age characters and count them:

class Solution {
    
    
    fun countSeniors(details: Array<String>): Int {
    
    
        return details.count {
    
     it.substring(11, 13).toInt() > 60 }
    }
}

In addition to converting strings to integers and then comparing, you can also directly compare the lexicographic order “60”of :

class Solution {
    
    
    fun countSeniors(details: Array<String>): Int {
    
    
        return details.count {
    
     it.substring(11, 13) > "60" }
    }
}

Complexity analysis:

  • Time complexity: O ( n ) O(n)O ( n ) where n is the length of the details array;
  • Space complexity: O ( 1 ) O(1)O ( 1 ) uses only constant level space.

T2. Sum in Matrix (Medium)

https://leetcode.cn/problems/sum-in-a-matrix/

Simple mock questions.

First sort each row, and then take the maximum value of each column.

class Solution {
    
    
    fun matrixSum(nums: Array<IntArray>): Int {
    
    
        var ret = 0
        for (row in nums) {
    
    
            row.sort()
        }
        for (j in 0 until nums[0].size) {
    
    
            var mx = 0
            for (i in 0 until nums.size) {
    
    
                mx = Math.max(mx, nums[i][j])
            }
            ret += mx
        }
        return ret
    }
}

Complexity analysis:

  • Time complexity: O ( nmlgm + nm ) O(nmlgm + nm)O(nmlgm+nm ) where n and m are the number of rows and columns of the matrix respectively, the sorting time isO ( nmlgm ) O(nmlgm)O ( nm l g m ) , scan timeO ( nm ) O(nm)O ( nm )
  • Space complexity: O ( lgm ) O(lgm)O ( l g m ) sorted recursion stack space.

T3. Maximum or value (Medium)

https://leetcode.cn/problems/maximum-or/

topic description

You are given an array   of integers with subscripts  starting at 0  and length   and an integer   . In each operation, you can choose a number and multiply it   .nnumsk2

You can perform at most  k operations, please return nums[0] | nums[1] | ... | nums[n - 1] the maximum value of **.

a | b Represents  the bitwise OR operation  of the sum of  a two  integers  .b

Example 1:

输入:nums = [12,9], k = 1
输出:30
解释:如果我们对下标为 1 的元素进行操作,新的数组为 [12,18] 。此时得到最优答案为 12 和 18 的按位或运算的结果,也就是 30 。

Example 2:

输入:nums = [8,1,2], k = 2
输出:35
解释:如果我们对下标 0 处的元素进行操作,得到新数组 [32,1,2] 。此时得到最优答案为 32|1|2 = 35 。

hint:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • 1 <= k <= 15

problem structuring

1. Summarize the problem goal

Computes the maximum or value that can be obtained.

2. Analyze the elements of the problem

In each operation, a number can be selected from the array and multiplied by 2, which is equivalent to shifting 1 bit to the left.

3. Observe the problem data

  • Data volume: The upper limit of the problem data volume is 1 0 5 10^5105 , the time complexity of the algorithm is required to be lower thanO ( n 2 ) O(n^2)O ( n2)
  • Data size: the upper bound of the element value is 1 0 9 10^9109 , the upper bound of the number of operations k is 15 (what is the use of this property?);
  • Output result: return the result in the form of Long integer.

4. Observe the test cases

Take Example 1 nums=[12, 9], k = 1 as an example, the optimal answer is to multiply 9 by 2, which shows that operating the maximum value does not necessarily obtain the maximum OR value.

5. Increase the level of abstraction

  • Weight: The higher the binary bit, the greater the impact on the size of the number, so we should try to make the binary position of the high bit 1;
  • Is it a decision problem? Since there are multiple location choices for each operation, this is a decision problem.

6. Specific solutions

  • 1. Greedy: Combined with the "data size" analysis, since the upper bound of the number of operations k is 15, the displacement will not overflow Long anyway. Therefore, we can apply k shift operations on the same number, and set the high bit position to 1 as much as possible;
  • 2. Dynamic programming (knapsack): Assuming that the maximum or value that can be formed by the first i - 1 elements of the array has been calculated, then consider splicing nums[i], you can choose not to operate nums[i], or you can choose to use nums[i] ] for x times, then the problem becomes the combined OR value of "the largest OR value of k - x operations in the first i - 1 elements" and "num[i] operations x times". "Maximum or value of k - x operations in the first i - 1 elements" This is a similar but smaller subproblem to the original problem, which can be solved by dynamic programming, and more specifically by the knapsack problem model.

Solution 1 (greedy + suffix decomposition)

Enumerate all numbers and shift to the left k times, calculate the optimal solution of all schemes:

class Solution {
    
    
    fun maximumOr(nums: IntArray, k: Int): Long {
    
    
        val n = nums.size
        // 前后缀分解
        val pre = IntArray(n + 1)
        val suf = IntArray(n + 1)
        for (i in 1 .. n) {
    
    
            pre[i] = pre[i - 1] or nums[i - 1]
        }
        for (i in n - 1 downTo 0) {
    
    
            suf[i] = suf[i + 1] or nums[i]
        }
        var ret = 0L
        for (i in nums.indices) {
    
    
            ret = Math.max(ret, (1L * nums[i] shl k) or pre[i].toLong() or suf[i + 1].toLong())
        }
        return ret
    }
}

Since each scheme requires the OR of n - 1 numbers before and after the enumeration, this is an O ( n 2 ) O(n^2)O ( n2 ), the solution will exceed the time limit. We can use the space-for-time strategy to pre-calculate the OR value of the prefix and suffix of each position (not included). This technique is "prefix and suffix decomposition".

In terms of implementation details, we can put one of the prefixes in the scanning process.

class Solution {
    
    
    fun maximumOr(nums: IntArray, k: Int): Long {
    
    
        val n = nums.size
        // 前后缀分解
        val suf = IntArray(n + 1)
        for (i in n - 1 downTo 0) {
    
    
            suf[i] = suf[i + 1] or nums[i]
        }
        var ret = 0L
        var pre = 0L
        for (i in nums.indices) {
    
    
            ret = Math.max(ret, pre or (1L * nums[i] shl k) or suf[i + 1].toLong())
            pre = pre or nums[i].toLong()
        }
        return ret
    }
}

Complexity analysis:

  • Time complexity: O ( n ) O(n)O ( n ) where n is the length of the nums array;
  • Space Complexity: O ( n ) O(n)O ( n ) suffix or value array length space.

Solution 2 (Dynamic Programming)

When using the knapsack problem model, define dp[i][j] to represent the maximum or value that can be obtained by operating k times on the first i elements, then:

  • 状态转移方程: d p [ i ] [ j ] = m a x d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − x ] ∣ ( n u m s [ i ] < < x ) dp[i][j] = max{dp[i-1][j], dp[i - 1][j - x] | (nums[i] << x)} dp[i][j]=max x d p [ i1][j],dp[i1][jx](nums[i]<<x)
  • Termination condition: dp [ n ] [ k ] dp[n][k]dp[n][k]
 class Solution {
    
    
    fun maximumOr(nums: IntArray, k: Int): Long {
    
    
        val n = nums.size
        // 以 i 为止,且移动 k 次的最大或值
        val dp = Array(n + 1) {
    
     LongArray(k + 1) }
        for (i in 1 .. n) {
    
    
            for (j in 0 .. k) {
    
    
                for (m in 0 .. j) {
    
    
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - m] or (1L * nums[i - 1] shl m) /* 移动 m 次 */)
                }
            }
        }
        return dp[n][k]
    }
}

In addition, this knapsack problem can cancel the item dimension to optimize space:

class Solution {
    
    
    fun maximumOr(nums: IntArray, k: Int): Long {
    
    
        val n = nums.size
        // 以 i 为止,且移动 k 次的最大或值
        val dp = LongArray(k + 1)
        for (i in 1 .. n) {
    
    
            // 逆序
            for (j in k downTo 0) {
    
    
                for (m in 0 .. j) {
    
    
                    dp[j] = Math.max(dp[j], dp[j - m] or (1L * nums[i - 1] shl m) /* 移动 m 次 */)
                }
            }
        }
        return dp[k]
    }
}
  • Time complexity: O ( n ⋅ k 2 ) O(n·k^2)O(nk2 )where n is the length of the nums array;
  • Space complexity: O ( k ) O(k)O ( k ) DP array space

Similar topics:


T4. Hero's Strength (Hard)

https://leetcode.cn/problems/power-of-heroes/

topic description

You are given an integer array whose subscript   starts  from 0nums  , which represents the hero's ability value. If we select some heroes,  the strength of this group of heroes  is defined as:

  • i0 , i1 , ...  ik represent the subscripts of this group of heroes in the array. Then the power of this group of heroes is  max(nums[i0],nums[i1] ... nums[ik])2 * min(nums[i0],nums[i1] ... nums[ik]) .

Please return the sum of the power of all possible  non-empty  hero groups   . Since the answer may be very large, please take  the remainder of the result.109 + 7 

Example 1:

输入:nums = [2,1,4]
输出:141
解释:
第 1 组:[2] 的力量为 22 * 2 = 8 。
第 2 组:[1] 的力量为 12 * 1 = 1 。
第 3 组:[4] 的力量为 42 * 4 = 64 。
第 4 组:[2,1] 的力量为 22 * 1 = 4 。
第 5 组:[2,4] 的力量为 42 * 2 = 32 。
第 6 组:[1,4] 的力量为 42 * 1 = 16 。
第 7 组:[2,1,4] 的力量为 42 * 1 = 16 。
所有英雄组的力量之和为 8 + 1 + 64 + 4 + 32 + 16 + 16 = 141 。

Example 2:

输入:nums = [1,1,1]
输出:7
解释:总共有 7 个英雄组,每一组的力量都是 1 。所以所有英雄组的力量之和为 7 。

hint:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109

problem structuring

1. Summarize the problem goal

Calculate the sum of the "power" of all combinations.

2. Analyze the elements of the problem

Enumerate all subsets, and calculate the strength value of the subset with the formula "maximum value 2 ∗ minimum value" "maximum value^2*minimum value"" Maximum2Minimum" .

3. Observe the problem data

  • Data volume: The upper limit of the problem data volume is 1 0 5 10^5105 , the time complexity of the algorithm is required to be lower thanO ( n 2 ) O(n^2)O ( n2)
  • Data size: the upper bound of the element value is 1 0 9 10^9109. The multiplication operation will overflow the upper bound of the integer, and the problem of large numbers needs to be considered.

4. Observation problem test cases:

Take the array nums=[1, 2, 3] as an example:

  • Analysis of small-scale problems: [] The power value of the empty set is 0, and the power value calculation of only a subset of elements is no problem;
Subset maximum value minimum value Strength
{} 0 0 0
{1} 1 1 1 2 ∗ 1 1^2*1 121
{2} 2 2 2 2 ∗ 2 2^2*2 222
{3} 3 3 3 2 ∗ 3 3^2*3 323
  • Analyze the subset problem of size 2:
Subset maximum value minimum value Strength
{1, 2} 2 1 2 2 ∗ 1 2^2*1 221
{1, 3} 3 1 3 2 ∗ 1 3^2*1 321
{2, 3} 3 2 3 2 ∗ 2 3^2*2 322
  • Analyze the subset problem of size 3:
Subset maximum value minimum value Strength
{1, 2, 3} 3 1 3 2 ∗ 1 3^2*1321

5. How to solve the problem

  • Method 1 (violent enumeration): If you enumerate all subsets and find the strength value of each subset, then the time complexity will reach a very high O ( n ⋅ 2 n ) O(n·2^n)O(n2n ), where there are2 n 2^n2n seed sets (a total of n numbers, each number has two states of selection and non-selection), each subset costsO ( n ) O(n)O ( n ) linear scan for max and min.

So far, the problem has fallen into a bottleneck. The solution is to repeat the above steps and enumerate the mastered data structures, algorithms and techniques to find ideas. The breakthrough lies in understanding the scale of the problem from another perspective (the idea of ​​dynamic programming).

6. Continue to observe the problem test cases

Also take the array nums = [1, 2, 3] as an example:

  • Consider the power value problem for the empty set:
Subset maximum value minimum value
{} 0 0
  • Considering the power value problem up to "1":
Subset maximum value minimum value
{} 0 0
{1} 1 1
  • Considering the problem of strength value up to "2":
Subset maximum value minimum value
{} 0 0
{1} 1 1
{2} 2 2
{1, 2} 2 1
  • Considering the power value up to "3":
Subset maximum value minimum value
{} 0 0
{1} 1 1
{2} 2 2
{1, 2} 2 1
{3} 3 3
{1,3} 3 1
{2,3} 3 2
{1,2,3} 3 1

What does this mean?

  • Key point 1 - Constructing subsets recursively:

We found that the subset problem can be constructed recursively. When we add a new element, we actually copy the existing subset and then add elements to the copied subset. For example, when we consider "2", we copy {} and {1} and add the element "2".

  • Key point 2 - Contribution of maximum value:

Since we are increasing elements from small to large, the maximum value in the new subset after copying must be equal to the current element, so the key to the problem is "how to calculate the minimum value of these new subsets".

  • Key point 3 - Contribution of the minimum value:

Since we use the method of subset replication to understand the problem of subset construction, it is easy to find that the earlier the number appears, the greater the number of occurrences of the minimum value (Doraemon's doubling potion).

For example, the number of subsets with the minimum value of 1 is 1 at the beginning, and the number of subsets with the minimum value of 1 after processing "2" is 2 times, so when "3" is processed, it will be accumulated 2 times with 1 as Minimum strength value: 2 ∗ ( 3 2 ∗ 1 ) 2*(3^2*1)2(321 ) . In the same way, the power value with the minimum value of 2 will be accumulated once:1 ∗ ( 3 ∗ 2 ∗ 2 ) 1*(3*2*2)1(322 ) , additionally accumulating {3} transferred from the empty set.

So far, the solution to the problem has gradually become clear.

7. New means of solving problems

  • Means 2 (dynamic programming):

Consider that there are five numbers a, b, c, d, e, arranged in order from small to large, and enumerated from small to large.

When enumerating to d, the new subset added by replication consists of:

  • There are 4 subsets with a as the minimum value: cumulative force value 4 ∗ ( d 2 ∗ a ) 4*(d^2*a)4(d2a)
  • There are 2 subsets with b as the minimum value: cumulative force value 2 ∗ ( d 2 ∗ b ) 2*(d^2*b)2(d2b)
  • There is 1 subset with c as the minimum value: cumulative force value 1 ∗ ( d 2 ∗ c ) 1*(d^2*c)1(d2c)

In addition, there is also a subset with d itself as the minimum value: cumulative force value 1 ∗ ( d 2 ∗ d ) 1*(d^2*d)1(d2d ) , the contribution of the left element of d to the result is s, thenpow ( d ) = d 2 ∗ ( s + d ) pow(d) = d^2*(s + d)pow(d)=d2(s+d)

Continuing to enumerate to e, the new subset added by replication includes:

  • There are 8 subsets with a as the minimum value: cumulative force value 8 ∗ ( e 2 ∗ a ) 8*(e^2*a)8(e2a)
  • There are 4 subsets with b as the minimum value: cumulative force value 4 ∗ ( e 2 ∗ b ) 4*(e^2*b)4(e2b)
  • There are 2 subsets with c as the minimum value: cumulative force value 2 ∗ ( e 2 ∗ c ) 2*(e^2*c)2(e2c)
  • There is 1 subset with d as the minimum value: cumulative force value 1 ∗ ( e 2 ∗ d ) 1*(e^2*d)1(e2d)

In addition, there is also a subset with e itself as the minimum value: cumulative force value 1 ∗ ( e 2 ∗ e ) 1*(e^2*e)1(e2e ) , the contribution of the element on the left side of e to the result is s`, thenpow ( e ) = e 2 ∗ ( s ' + e ) pow(e) = e^2*(s` + e)pow(e)=e2(s+e)

Observe the relationship between s and s`:

s = 4 ∗ a + 2 ∗ b + 1 ∗ c s = 4*a + 2*b + 1*c s=4a+2b+1c

s = 8 ∗ a + 4 ∗ b + 2 ∗ c + d = s ∗ 2 + d s = 8*a + 4*b + 2*c + d = s*2 + d s=8a+4b+2c+d=s2+d

This shows that we can maintain the contribution s of the left element of each element, and use s to calculate the power value of all new subsets of the current element, and the time complexity only needs O(1)!

[4,3,2,1]
 1 1 2 4
追加 5:
[5,4,3,2,1]
 1 1 2 4 8

Solution (Dynamic Programming)

According to the recursive formula obtained from the problem analysis, recursive simulation can be used, and the large number problem is not considered first:

class Solution {
    
    
    fun sumOfPower(nums: IntArray): Int {
    
    
        var ret = 0L
        // 排序
        nums.sort()
        // 影响因子
        var s = 0L
        for (x in nums) {
    
    
            ret += (x * x) * (s + x)
            s = s * 2 + x
        }
        return ret.toInt()
    }
}

Consider the large number problem again:

class Solution {
    
    
    fun sumOfPower(nums: IntArray): Int {
    
    
        val MOD = 1000000007
        var ret = 0L
        // 排序
        nums.sort()
        // 影响因子
        var s = 0L
        for (x in nums) {
    
    
            ret = (ret + (1L * x * x % MOD) * (s + x)) % MOD // x*x 也可能溢出
            s = (s * 2 + x) % MOD
        }
        return ret.toInt()
    }
}

In actual combat, I use the method of calculating the maximum impact factor first, and then accumulating:

class Solution {
    
    
    fun sumOfPower(nums: IntArray): Int {
    
    
        val MOD = 1000000007
        var ret = 0L
        val n = nums.size
        // 排序
        nums.sortDescending()
        // 影响因子
        var s = 0L
        var p = 1L
        for (i in 1 until n) {
    
    
            s = (s + nums[i] * p) % MOD 
            p = (2 * p) % MOD
        }
        // 枚举子集
        for (i in 0 until n) {
    
    
            val x = nums[i]
            ret = (ret + x * x % MOD * (s + x)) % MOD
            if (i < n - 1) {
    
    
                s = (s - nums[i + 1]) % MOD
                if (s and 1L != 0L) {
    
    
                    s += MOD // 奇数除 2 会丢失精度
                }
                s = (s / 2) % MOD
            }
        }
        return ret.toInt()
    }
}

Complexity analysis:

  • Time complexity: O ( nlgn ) O(nlgn)O ( n l g n ) where n is the length of the nums array, the bottleneck is in sorting, and the time complexity of calculating the power value is O(n);
  • Space Complexity: O ( lgn ) O(lgn)O ( l g n ) sorted recursion stack space.

Past review

Guess you like

Origin blog.csdn.net/pengxurui/article/details/130675639