面试题51. 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 1:

输入: [7,5,6,4]

输出: 5

限制:

0 <= 数组长度 <= 50000

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

方法一:BF法(超时)

  1. class Solution {
  2. public:
  3. int reversePairs(vector<int>& nums) {
  4. int size = nums.size();
  5. if(size <= 1)
  6. return 0;
  7. int ret = 0;
  8. for(int i = 0; i < size; i++)
  9. {
  10. int tmp = nums[i];
  11. for(int j = i + 1; j < size; j++)
  12. {
  13. if(tmp > nums[j])
  14. ret++;
  15. }
  16. }
  17. return ret;
  18. }
  19. };

方法二:后退法(超时)

  1. class Solution {
  2. public:
  3. int reversePairs(vector<int>& nums) {
  4. int size = nums.size();
  5. if(size <= 1)
  6. return 0;
  7. int ret = 0;
  8. map<int, int>store;
  9. for(int i = size - 1; i >= 0; i--)
  10. {
  11. int tmp = nums[i];
  12. store[tmp]++;
  13. for(auto &index : store)
  14. {
  15. if(index.first == tmp)
  16. break;
  17. else
  18. ret += index.second;
  19. }
  20. }
  21. return ret;
  22. }
  23. };

方法三:归并排序

  1. class Solution {
  2. public:
  3. int mergeSort(vector<int>& nums, vector<int>& tmp, int l, int r)
  4. {
  5. if(l >= r)
  6. return 0;
  7. int mid = (l + r) / 2;
  8. int inv_count = mergeSort(nums, tmp, 1, mid) + mergeSort(nums, tmp, mid+1, r);
  9. //合并数组时计算逆序对个数
  10. int i = 1, j = mid + 1, pos = 1;
  11. while(i <= mid && j <= r){
  12. if(nums[i] <= nums[i]) {
  13. tmp[pos] = nums[i];
  14. ++i;
  15. inv_count += (j - (mid + 1));
  16. }
  17. else {
  18. tmp[pos] = nums[j];
  19. ++j;
  20. }
  21. ++pos;
  22. }
  23. for(int k = i; k <= mid; ++k)
  24. {
  25. tmp[pos++] = nums[k];
  26. inv_count += (j - (mid + 1));
  27. }
  28. }
  29. }
  1. public class Solution {
  2. public int reversePairs(int[] nums) {
  3. int len = nums.length;
  4. if (len < 2) {
  5. return 0;
  6. }
  7. int[] copy = new int[len];
  8. for (int i = 0; i < len; i++) {
  9. copy[i] = nums[i];
  10. }
  11. int[] temp = new int[len];
  12. return reversePairs(copy, 0, len - 1, temp);
  13. }
  14. /**
  15. * nums[left..right] 计算逆序对个数并且排序
  16. *
  17. * @param nums
  18. * @param left
  19. * @param right
  20. * @param temp
  21. * @return
  22. */
  23. private int reversePairs(int[] nums, int left, int right, int[] temp) {
  24. if (left == right) {
  25. return 0;
  26. }
  27. int mid = left + (right - left) / 2;
  28. int leftPairs = reversePairs(nums, left, mid, temp);
  29. int rightPairs = reversePairs(nums, mid + 1, right, temp);
  30. if (nums[mid] <= nums[mid + 1]) {
  31. return leftPairs + rightPairs;
  32. }
  33. int crossPairs = mergeAndCount(nums, left, mid, right, temp);
  34. return leftPairs + rightPairs + crossPairs;
  35. }
  36. /**
  37. * nums[left..mid] 有序,nums[mid + 1..right] 有序
  38. *
  39. * @param nums
  40. * @param left
  41. * @param mid
  42. * @param right
  43. * @param temp
  44. * @return
  45. */
  46. private int mergeAndCount(int[] nums, int left, int mid, int right, int[] temp) {
  47. for (int i = left; i <= right; i++) {
  48. temp[i] = nums[i];
  49. }
  50. int i = left;
  51. int j = mid + 1;
  52. int count = 0;
  53. for (int k = left; k <= right; k++) {
  54. if (i == mid + 1) {
  55. nums[k] = temp[j];
  56. j++;
  57. } else if (j == right + 1) {
  58. nums[k] = temp[i];
  59. i++;
  60. } else if (temp[i] <= temp[j]) {
  61. nums[k] = temp[i];
  62. i++;
  63. } else {
  64. nums[k] = temp[j];
  65. j++;
  66. count += (mid - i + 1);
  67. }
  68. }
  69. return count;
  70. }
  71. }

时间复杂度:同归并排序O(nlogn)
空间复杂度:同归并排序O(n),因为归并排序需要用到一个临时数组