LeetCode(困难)数组中的逆序对(c#)

题目为 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
在这里插入图片描述
这道题可以当作例题做,思路为归并排序。不理解什么是归并排序可以看我的文章 排序算法之插入排序、希尔排序、归并排序(C#)。当两个有序数组进行合并时,左侧有比右侧大的元素,则左侧该元素之后所有之后的元素均为逆序对。一开始我的代码为

public class Solution {
    public int ReversePairs(int[] nums) {
        if (nums.Count()==0||nums.Count()==1)
            {
                return 0;
            }
            ReversePairsSec(nums);
            return Reverseres;
    }
   	public int[] ReversePairsSec(int[] nums)
        {
            if (nums.Count()==1)
            {
                return nums;
            }
            int count = nums.Count();
            int half = count / 2;
            int[] left = nums.Take(half).ToArray();
            int[] right = nums.Skip(half).ToArray();
            int[] leftNew= ReversePairsSec(left);
            int[] rightNew= ReversePairsSec(right);
            return MergeSortPairs(leftNew, rightNew);
        }
        int Reverseres = 0;
        public int[] MergeSortPairs(int[] numsLeft,int[] numsRight)
        {
            int leftPos = 0, rightPos = 0;
            List<int> resTemp = new List<int>();
            while (leftPos<numsLeft.Count()&&rightPos<numsRight.Count())
            {
                if (numsLeft[leftPos]>numsRight[rightPos])
                {
                    Reverseres += (numsLeft.Count() - leftPos);
                    resTemp.Add(numsRight[rightPos]);
                    rightPos++;
                }
                else
                {
                    resTemp.Add(numsLeft[leftPos]);
                    leftPos++;
                }
            }
            if (rightPos < numsRight.Count())
            {
                resTemp.AddRange(numsRight.Skip(rightPos));
            }
            if (leftPos < numsLeft.Count())
            {
                resTemp.AddRange(numsLeft.Skip(leftPos));
            }
            return resTemp.ToArray();
        }
}

效率不高,参照其他题解更改后,优化代码为

public class Solution {
    public int ReversePairs(int[] nums)
    {
        if (nums == null || nums.Length < 2)
        {
            return 0;
        }

        var copy = new int[nums.Length];
        Array.Copy(nums, copy, nums.Length);

        var tmpArr = new int[nums.Length];

        return ReversePairs(copy, 0, nums.Length - 1, tmpArr);
    }

    private int ReversePairs(int[] nums, int left, int right, int[] tmpArr)
    {
        if (left == right)
        {
            return 0;
        }

        int middle = left + ((right - left) >> 1);
        int leftCount = ReversePairs(nums, left, middle, tmpArr); // 归
        int rightCount = ReversePairs(nums, middle + 1, right, tmpArr);// 归
        int crossCount = MergeAndCount(nums, left, middle, right, tmpArr); // 并

        return leftCount + rightCount + crossCount;
    }

    private int MergeAndCount(int[] nums, int left, int middle, int right, int[] tmpArr)
    {
        // 重复使用tmpArr, 减少每次重建数组和销毁数组的开销
        for (int i = left; i <= right; i++)
        {
            tmpArr[i] = nums[i];
        }
        int count = 0;
        int leftIndex = left;
        int rightIndex = middle + 1;

        int tmpArrIndex = left;

        while (leftIndex <= middle && rightIndex <= right)
        {
            if (tmpArr[leftIndex] <= tmpArr[rightIndex])
            {
                nums[tmpArrIndex++] = tmpArr[leftIndex++];
            }
            else
            {
                nums[tmpArrIndex++] = tmpArr[rightIndex++];
                count += middle - leftIndex + 1;
            }
        }

        if (leftIndex <= middle)
        {
            for (int i = leftIndex; i <= middle; i++)
            {
                nums[tmpArrIndex++] = tmpArr[i];
            }
        }

        if (rightIndex <= right)
        {
            for (int i = rightIndex; i <= right; i++)
            {
                nums[tmpArrIndex++] = tmpArr[i];
            }
        }
        return count;
    }
}

对比了一下原因,因为第一个的代码有很多的ToArray()使用,占用时间。另外就是每次遍历都要新建数组,占用时间和空间。而第二版代码就节省了很多,都在Nums上操作和一个临时数组操作。节省空间。且没有数组转换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值