[leetcode]315. Count of Smaller Numbers After Self
2016-07-20 11:04
489 查看
问题描述
You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].
Example:
Given nums = [5, 2, 6, 1]
To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1 smaller element (1).
To the right of 6 there is 1 smaller element (1).
To the right of 1 there is 0 smaller element.
Return the array [2, 1, 1, 0].
最开始由编程之美的光影切割问题中求逆序対找到这道题,网上有很多非常巧妙的解法,自己实现了两种。
因为要保存原来的顺序,所以没有直接改写数组,而是用一个pos数组来存储对应的位置。参考博客http://blog.csdn.net/jmspan/article/details/51219203
参考博客http://www.cnblogs.com/bigchencheng/p/5151382.html
这种方法虽然空间上存在一定限制,但是避免了用二分求改变原数组,因此在这道题上,时间是最短的。
参考地址https://discuss.leetcode.com/topic/31154/complicated-segmentree-solution-hope-to-find-a-better-one
本题还可以利用二叉搜索树、线段树的方法来解,详细说明参看博客http://www.cnblogs.com/yrbbest/p/5068550.html
You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].
Example:
Given nums = [5, 2, 6, 1]
To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1 smaller element (1).
To the right of 6 there is 1 smaller element (1).
To the right of 1 there is 0 smaller element.
Return the array [2, 1, 1, 0].
最开始由编程之美的光影切割问题中求逆序対找到这道题,网上有很多非常巧妙的解法,自己实现了两种。
方法一:改写归并
private static void reverse(int[] nums, int[] smaller, int[] pos, int start, int end){ if(start>=end){ return ; } int mid=start+(end-start)/2; reverse(nums, smaller, pos, start, mid); reverse(nums, smaller, pos, mid+1, end); int[] temp=new int[end-start+1]; int i=start, j=mid+1, k=0; int count=0; while(i<=mid||j<=end){ if(i>mid){ temp[k++]=pos[j++]; }else if(j>end){ smaller[pos[i]]+=count; temp[k++]=pos[i++]; }else if(nums[pos[i]]<=nums[pos[j]]){ smaller[pos[i]]+=count; temp[k++]=pos[i++]; }else{ count++; temp[k++]=pos[j++]; } } for(i=0; i<k; i++){ pos[start+i]=temp[i]; } } public static List<Integer> countSmaller(int[] nums) { List<Integer> re=new ArrayList<Integer>(); if(nums==null||nums.length==0){ return re; } int[] smaller=new int[nums.length]; int[] pos=new int[nums.length]; for(int i=0; i<pos.length; i++){ pos[i]=i; } reverse(nums, smaller, pos, 0, nums.length-1); for(int i=0; i<smaller.length; i++){ re.add(smaller[i]); } return re; }
因为要保存原来的顺序,所以没有直接改写数组,而是用一个pos数组来存储对应的位置。参考博客http://blog.csdn.net/jmspan/article/details/51219203
方法二:树状数组
学习了树状数组和线段树这两种数据结构。下面是用树状数组实现的代码
private static int[] tree; //方法1、通过二分查找 public static List<Integer> countSmaller(int[] nums) { int[] temp=nums.clone(); Arrays.sort(temp); for(int i=0; i<nums.length; i++){ nums[i]=Arrays.binarySearch(temp, nums[i]); } tree=new int[nums.length]; Integer[] re=new Integer[nums.length]; for(int i=nums.length-1; i>=0; i--){ re[i]=sumRange(nums[i]); add(nums[i]+1, 1); } return Arrays.asList(re); } private static void add(int index, int val){ while(index<tree.length){ tree[index]+=val; index+=lowBit(index); } } private static int sumRange(int index){ int re=0; while(index>0){ re+=tree[index]; index-=lowBit(index); } return re; } private static int lowBit(int index){ return index&(-index); }
参考博客http://www.cnblogs.com/bigchencheng/p/5151382.html
当然树状数组还有改进的空间,上面把原数组通过二分查找改成0-nums.length的新数组,这样虽然改变了数值,但是相对大小是不变的,因此对答案没有影响。在leetcode讨论区有人给出了如下的改进。
public static List<Integer> countSmaller2(int[] nums) { pre(nums); tree=new int[11000]; Integer[] re=new Integer[nums.length]; for(int i=nums.length-1; i>=0; i--){ re[i]=sumRange(nums[i]); add(nums[i]+1, 1); } return Arrays.asList(re); } private static void pre(int[] nums){ int min=Integer.MAX_VALUE; for(int num: nums){ min=Math.min(min, num); } if(min<0){ min=-min+1; for(int i=0; i<nums.length; i++){ nums[i]+=min; } } }
这种方法虽然空间上存在一定限制,但是避免了用二分求改变原数组,因此在这道题上,时间是最短的。
参考地址https://discuss.leetcode.com/topic/31154/complicated-segmentree-solution-hope-to-find-a-better-one
本题还可以利用二叉搜索树、线段树的方法来解,详细说明参看博客http://www.cnblogs.com/yrbbest/p/5068550.html
相关文章推荐
- leetcode 179 Largest Number
- leetcode 24 Swap Nodes in Pairs
- leetcode 2 Add Two Numbers 方法1
- leetcode 2 Add Two Numbers 方法2
- leetcode----Longest Substring Without Repeating Characters
- [LeetCode]47 Permutations II
- [LeetCode]65 Valid Number
- [LeetCode]123 Best Time to Buy and Sell Stock III
- [LeetCode] String Reorder Distance Apart
- [LeetCode] Sliding Window Maximum
- [LeetCode] Find the k-th Smallest Element in the Union of Two Sorted Arrays
- [LeetCode] Determine If Two Rectangles Overlap
- [LeetCode] A Distance Maximizing Problem
- leetcode_linearList
- leetcode_linearList02
- 021-Merge Two Sorted Lists(合并两个排好序的单链表);leetcode
- LeetCode[Day 1] Two Sum 题解
- LeetCode[Day 2] Median of Two Sorted Arrays 题解
- LeetCode[Day 3] Longest Substring Without... 题解
- LeetCode [Day 4] Add Two Numbers 题解