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;
}

 

posted @ 2016-07-01 22:44  Hesier  阅读(445)  评论(0编辑  收藏  举报