归并分治 前置知识:讲解021-归并排序
补充:
【举个栗子】假设数组 s = [1,3,5,2,4,6],给定一个数组arr,实现函数返回arr的“小和”
在s[0]的左边所有 <= s[0]的数的总和为0
在s[1]的左边所有 <= s[1]的数的总和为1
在s[2]的左边所有 <= s[2]的数的总和为4
在s[3]的左边所有 <= s[3]的数的总和为1
在s[4]的左边所有 <= s[4]的数的总和为6
在s[5]的左边所有 <= s[5]的数的总和为15
所以s数组的 “小和” 为:0 + 1 + 4 + 1 + 6 + 15 = 27
C++代码:
- #include
- using namespace std;
- #include
-
- // 返回跨左右产生的小和累加和,左侧有序、右侧有序,让左右两侧整体有序
- // arr[left...mid] arr[mid+1...right]
- long merge(vector<int>& arr,int left, int mid, int right) {
- int n = right - left + 1;
- vector<int> help(n, 0);
- // 统计部分
- long ans = 0;
- for (int j = mid + 1, i = left, sum = 0; j <= right; j++) {
- while (i <= mid && arr[i] <= arr[j]) {
- sum += arr[i++];
- }
- ans += sum;
- }
- // 正常merge
- int i = 0;
- int a = left;
- int b = mid + 1;
- while (a <= mid && b <= right) {
- help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
- }
- while (a <= mid) {
- help[i++] = arr[a++];
- }
- while (b <= right) {
- help[i++] = arr[b++];
- }
- for (i = 0; i < n; i++) {
- arr[i+left] = help[i];
- }
- return ans;
- }
-
- // 结果比较大,用 int 会溢出的,所以返回 long 类型
- // 特别注意溢出这个点,笔试常见坑
- // 返回arr[left...right]范围上,小和的累加和,同时把arr[left...right]变有序
- long smallSum(vector<int>&arr, int left, int right) {
- if (left == right) return 0;
- //int mid = (left + right) / 2;
- int mid = left + ((right - left) >> 1);
- return smallSum(arr,left, mid) + smallSum(arr,mid + 1, right) + merge(arr,left, mid, right);
- }
-
- int main() {
- vector<int>arr = { 7,7,6,2,6,5,4,9 };
- //vector
arr = { 1, 3, 5, 2, 4, 6 }; - int n = arr.size();
- cout<<"该数组的小和为:"<<smallSum(arr,0, n - 1)<
- system("pause");
- return 0;
- }
- 实战牛客网的[编程题]计算数组的小和
- #include
- #include
- using namespace std;
- // 返回跨左右产生的小和累加和,左侧有序、右侧有序,让左右两侧整体有序
- // arr[left...mid] arr[mid+1...right]
- long merge(vector<int>& arr, int left, int mid, int right) {
- int n = right - left + 1;
- vector<int> help(n, 0);
- // 统计部分
- long ans = 0;
- for (int j = mid + 1, i = left, sum = 0; j <= right; j++) {
- while (i <= mid && arr[i] <= arr[j]) {
- sum += arr[i++];
- }
- ans += sum;
- }
- // 正常merge
- int i = 0;
- int a = left;
- int b = mid + 1;
- while (a <= mid && b <= right) {
- help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
- }
-
- while (a <= mid) {
- help[i++] = arr[a++];
- }
- while (b <= right) {
- help[i++] = arr[b++];
- }
- for (i = 0; i < n; i++) {
- arr[i + left] = help[i];
- }
- return ans;
- }
-
-
- // 结果比较大,用 int 会溢出的,所以返回 long 类型
- // 特别注意溢出这个点,笔试常见坑
- // 返回arr[left...right]范围上,小和的累加和,同时把arr[left...right]变有序
- long smallSum(vector<int>& arr, int left, int right) {
- if (left == right) return 0;
- //int mid = (left + right) / 2;
- int mid = left + ((right - left) >> 1);
- return smallSum(arr, left, mid) + smallSum(arr, mid + 1, right) + merge(arr, left, mid, right);
- }
-
- int main() {
- int n;
- cin >> n;
- vector<int> arr(n, 0);
- for (int i = 0; i < n; i++) cin >> arr[i];
- cout << smallSum(arr, 0, n - 1) << endl;
- return 0;
- }
参考和推荐视频: