Content
043 Multiply Strings(M)
Description
输入为字符串表示的整数,输出二者的乘积,用字符串表示。不能直接把字符串转换为整数)。
Analysis & Solution
根据整数竖式乘法规则,可以发现以下规律:
整数A的第i位和整数B的第j位的乘积最终会出现在整数AB的第(i+j)位。
算法步骤为先将输入的两个字符串反转存入整数数组,根据以上规律,求出乘积每一位未处理进位前的值。然后处理进位,同时将结果转换为字符串,反转后输出。
Code
class Solution {
public:
string multiply(string num1, string num2) {
string ans;
vector<int> a, b, c;
c.resize(num1.size() + num2.size() - 1);
for (int i = num1.size() - 1; i >= 0; i--) a.push_back(num1[i] - '0');
for (int i = num2.size() - 1; i >= 0; i--) b.push_back(num2[i] - '0');
for (int i = 0; i < a.size(); i++) {
for (int j = 0; j < b.size(); j++) {
c[i + j] += a[i] * b[j];
}
}
int k = 0;
for (int i = 0; i < c.size(); i++) {
k += c[i];
char c = k % 10 + '0';
ans = c + ans;
k /= 10;
}
while (k) {
char c = k % 10 + '0';
ans = c + ans;
k /= 10;
}
while (ans.size() > 1 && ans[0] == '0') ans.erase(ans.begin());
return ans;
}
};
时间复杂度:涉及一次两层循环,时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
046 Permutations(M)
Description
题意为给出一个数组,求出数组所有元素的全排列并输出。
Analysis & Solution
本题用到的是回溯算法,先直接放上代码。
Code
vector<vector<int>> res;
vector<int> tempRes;
vector<int> flag;
void backtrack(vector<int>& nums)
{
if(tempRes.size() == nums.size())
{
res.push_back(tempRes);
return;
}
for(int i = 0; i < flag.size(); i++)
{
if(flag[i] == 1) continue;
flag[i] = 1;
tempRes.push_back(nums[i]);
backtrack(nums);
tempRes.pop_back();
flag[i] = 0;
}
return;
}
vector<vector<int>> permute(vector<int>& nums)
{
if(nums.size() == 0) return {{}};
flag = vector<int>(nums.size(), 0);
backtrack(nums);
return res;
}
时间复杂度:仅对数组扫描一次,因此复杂度为 O ( n ) O(n) O(n)。
053 Maximum Subarray(E)
Description
求最大子数组和,非常经典的算法问题,解法也比较多。
Analysis & Solution
(1)分治
用二分法,每次将数组按下标从中间等分,那么整个数组的最大子数组和就是左半数组的结果,右半数组的结果,横跨左右两部分结果的最大值。
左右两部分可以用递归解决,终止条件为仅有一个元素,返回元素本身。
横跨左右部分则用两个指针从中间分别向两边移动,直到扫过位置的和不再增大。
(2)动态规划
最优子结构
d
p
[
i
]
dp[i]
dp[i]表示以数组第i项A[i]结尾且包含A[i]的最大子数组和。
状态转移方程:
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
1
]
+
A
[
i
]
,
A
[
i
]
)
dp[i]=max(dp[i-1]+A[i], A[i])
dp[i]=max(dp[i−1]+A[i],A[i])
解释:两种选择,要么包含前i-1项子问题的结果,要么前面的全舍弃,只留A[i]。求这两种选择的结果的最大值。
Code
//dp
int maxSubArray(vector<int>& nums)
{
int N = nums.size();
int dp[N];
memset(dp, 0, sizeof(dp));
dp[0] = nums[0];
int maxSum = dp[0];
for(int i = 1; i < N; i++)
{
dp[i] = max(dp[i-1] + nums[i], nums[i]);
if(dp[i] > maxSum) maxSum = dp[i];
}
return maxSum;
}
//divide and conquer
int MaxSubarray(vector<int>& A, int left, int right)
{
if(left == right)
return A[left];
int mid = (left + right) / 2;
int maxSumLeft = MaxSubarray(A, left, mid);
int maxSumRight = MaxSubarray(A, mid + 1, right);
int maxSumMidL = A[mid], maxSumMidR = A[mid + 1];
int currentSum = 0;
int i = mid, j = mid + 1;
while(i >= left)
{
currentSum += A[i];
maxSumMidL = max(maxSumMidL, currentSum);
i--;
}
currentSum = 0;
while(j <= right)
{
currentSum += A[j];
maxSumMidR = max(maxSumMidR, currentSum);
j++;
}
return max(max(maxSumLeft, maxSumRight), maxSumMidL + maxSumMidR);
}
时间复杂度:分治的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),动态规划的时间复杂度为 O ( n ) O(n) O(n)。