LintCode 数组(一)
恢复旋转排序数组
最大子数组
三数之和
加一
删除元素
删除排序数组中的重复数字
合并排序数组
将一个数组中的 0
移动到数组的最后面,非零元素保持原数组的顺序。必须在原数组上操作。
public void moveZeroes(int[] nums) { if(nums==null || nums.length==0){ return; } int insertPos = 0; for(int i=0; i<nums.length; i++){ if(nums[i]!=0){ nums[insertPos++] = nums[i]; } } while(insertPos<nums.length){ nums[insertPos++] = 0; } }
样例:nums1 = [1, 2, 2, 1]
, nums2 = [2, 2]
, 返回 [2]
.
解答一:用两个HashSet
public int[] intersection(int[] nums1, int[] nums2) { Set<Integer> set = new HashSet<Integer>(); Set<Integer> inter = new HashSet<>(); for(int i=0; i<nums1.length; i++){ set.add(nums1[i]); } for(int j=0; j<nums2.length; j++){ if(set.contains(nums2[j])){ inter.add(nums2[j]); } } int[] rst = new int[inter.size()]; int k = 0; for(Integer s: inter){ rst[k++] = s; } return rst; }
解答二:对两个数组排序,然后各用一个指针遍历。
public int[] intersection(int[] nums1, int[] nums2) { Set<Integer> set = new HashSet<Integer>(); Arrays.sort(nums1); Arrays.sort(nums2); int i=0, j=0; while(i<nums1.length && j<nums2.length){ if(nums1[i]<nums2[j]){ i++; }else if(nums1[i]>nums2[j]){ j++; }else{ set.add(nums1[i]); i++; j++; } } int[] arr = new int[set.size()]; int k = 0; for(Integer s: set){ arr[k++] = s; } return arr; }
解答三:利用HashMap
public int[] intersection(int[] nums1, int[] nums2){ Map<Integer, Integer> map = new HashMap<>(); for(int i = 0; i < nums1.length; ++i){ if(!map.containsKey(nums1[i])){ map.put(nums1[i], 1); } } List<Integer> list = new ArrayList<>(); for(int i = 0; i < nums2.length; ++i){ if(map.containsKey(nums2[i])){ list.add(nums2[i]); map.remove(nums2[i]); } } int[] res = new int[list.size()]; int k = 0; for(Integer num : list){ res[k++] = num; } return res; }
解答四:对num2排序,然后遍历num1中的数,在num2中进行二分查找,找到就放入set中。
给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。
public int[] twoSum(int[] numbers, int target) { HashMap<Integer, Integer> hash = new HashMap<>(); int[] result = new int[2]; for(int i=0; i<numbers.length; i++){ if(hash.get(numbers[i]) == null){ hash.put(target-numbers[i], i); }else{ result[0] = hash.get(numbers[i]) +1; result[1] = i + 1; } } return result; }
恢复旋转排序数组
给定一个旋转排序数组,在原地恢复其排序。
public void recoverRotatedSortedArray(ArrayList<Integer> nums) { for(int i=0; i<nums.size()-1; i++){ if(nums.get(i)>nums.get(i+1)){ recover(nums, 0, i); recover(nums, i+1, nums.size()-1); recover(nums, 0, nums.size()-1); } } } private void recover(ArrayList<Integer> nums, int left, int right){ while(left<right){ int tmp = nums.get(left); nums.set(left, nums.get(right)); nums.set(right, tmp); left++; right--; } }
最大子数组和
给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。
解答一:暴力
public int maxSubArray(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int maxSum = Integer.MIN_VALUE; for(int i=0; i<nums.length; i++){ int sum = 0; for(int j=i; j<nums.length; j++){ sum += nums[j]; maxSum = Math.max(maxSum, sum); } } return maxSum; }
解答二:动态规划。遍历,一个变量保存到当前位置时的最大值,另一个变量保存全局最大值。
public int maxSubArray(int[] nums) { int maxEndingHere = nums[0]; // 当前位置的最大值 int max = nums[0]; // 全局最大值 for(int i=1; i<nums.length; i++){ maxEndingHere = Math.max(nums[i], maxEndingHere+nums[i]); max = Math.max(max, maxEndingHere); } return max; }
解答三:贪婪算法。遍历,对所有数从左到右累加,同时判断选择最大和,如果当前sum为负,则再加下一个数时,把sum替换为0。
public int maxSubArray(int[] nums){ int max = Integer.MIN_VALUE; int sum = 0; for(int i=0; i<nums.length; i++){ sum += nums[i]; max = Math.max(max, sum); sum = Math.max(0, sum); //如果sum出现负,就不用在此sum为负的基础上再加下一个数。把sum改成0 } return max; }
加一
给定一个非负数,表示一个数字数组,在该数的基础上+1,返回一个新的数组。
样例:给定 [1,2,3]
表示 123, 返回 [1,2,4]
. 给定 [9,9,9]
表示 999, 返回 [1,0,0,0]
.
public int[] plusOne(int[] digits) { int carries = 1; for(int i=digits.length-1; i>=0 && carries>0; i--){ int sum = digits[i] + carries; digits[i] = sum % 10; carries = sum/10; } if(carries==0){ return digits; } int[] rst = new int[digits.length+1]; rst[0] = 1; for(int j=0; j<digits.length; j++){ rst[j+1] = digits[j]; } return rst; }
删除元素
给定一个数组和一个值,在原地删除与值相同的数字,返回新数组的长度。
解答:用左右两个指针,left的值为val时,把right赋给left,right--
public int removeElement(int[] nums, int val) { int left = 0; int right = nums.length-1; while(left<=right){ if(nums[left]==val){ nums[left] = nums[right]; right--; }else{ left++; } } return right+1; }
买卖股票的最佳时机
假设有一个数组,它的第i个元素是一支给定的股票在第i天的价格。如果你最多只允许完成一次交易(例如,一次买卖股票),设计一个算法来找出最大利润。
样例:给出一个数组样例 [3,2,3,1,2], 返回 1
解答:遍历数组,每次都更新最大利润和最小值。
public int maxProfit(int[] prices) { if(prices==null || prices.length==0){ return 0; } int min = prices[0]; int maxpro = 0; for(int i=1; i<prices.length; i++){ maxpro = Math.max(maxpro, prices[i]-min); min = Math.min(min, prices[i]); } return maxpro; }
删除排序数组中的重复数字
给定一个排序数组,在原数组中删除重复出现的数字,使得每个元素只出现一次,并且返回新的数组的长度。
解答:两个指针。i从头到尾遍历数组,遇到不同的,把值赋给count
public int removeDuplicates(int[] nums) { int count = 1; for(int i=1; i<nums.length; i++){ if(nums[i]!=nums[count-1]){ nums[count++] = nums[i]; } } return count; }
合并排序数组
(一)两个数组A,B。A中个数为m,B中个数为n。假设A有足够的容量,把B合并到A中,成为一个有序数组。
public void merge(int[] A, int m, int[] B, int n){ int i = m-1; int j = n-1; int k = m+n-1; while(i>=0 && j>=0){ if(A[i] > B[j]){ A[k--] = A[i--]; }else{ A[k--] = B[j--]; } } while(i>=0){ A[k--] = A[i--]; } while(j>=0){ A[k--] = B[j--]; } }
(二)合并两个排序的整数数组A和B变成一个新的数组。
public int[] mergeSortedArray(int[] A, int[] B) { int lena = A.length; int lenb = B.length; int[] rst = new int[lena+lenb]; int i=0, j=0, k=0; while(i<lena && j<lenb){ if(A[i]<=B[j]){ rst[k++] = A[i++]; }else{ rst[k++] = B[j++]; } } while(i<lena){ rst[k++] = A[i++]; } while(j<lenb){ rst[k++] = B[j++]; } return rst; }
三数之和
给出一个有n个整数的数组S,在S中找到三个整数a, b, c,找到所有使得a + b + c = 0的三元组。
解答:先把数组排序。用三个指针,i从头到尾遍历,left=i+1,right=length-1。把这三个数相加,结果小于0则i++,大于0则j--。
public ArrayList<ArrayList<Integer>> threeSum(int[] numbers) { ArrayList<ArrayList<Integer>> list = new ArrayList<>(); if(numbers==null || numbers.length<3){ return list; } Arrays.sort(numbers); for(int i=0; i<numbers.length-2; i++){ int left = i+1; int right = numbers.length-1; while(left<right){ int sum = numbers[i] + numbers[left] + numbers[right]; if(sum==0){ ArrayList<Integer> tmp = new ArrayList<>(); tmp.add(numbers[i]); tmp.add(numbers[left]); tmp.add(numbers[right]); if(list.contains(tmp) == false){ list.add(tmp); } left++; right--; }else if(sum < 0){ left++; }else{ right--; } } } return list; }