LeetCode刷题之路-Array

Array

刷LeetCode,按照LeetCode中分类的顺序由易到难开刷

27. Remove Element

https://leetcode.com/problems/remove-element/
挺简单的题目,看了别人的答案才意识到只需要返回新数组的长度,方法复杂度均为O(n)
我的代码:

public class Solution {
    public int removeElement(int[] nums, int val) {
        int i = 0;
        int j = 0;
        for(i = 0; i < nums.length; i++)
        {
            if(nums[i] == val)
            {
                continue;
            }
            else
            {
                nums[j] = nums[i];
                j++;
            }
        }
        return j;
    }
}

给出的最优方法也差不多,只是每次将查出的元素用当前数组的最后一个元素替换,继续搜索

public class Solution {
    public int removeElement(int[] nums, int val) {
        int len = nums.length;
        for(int i = 0; i < len; i++)
        {
            if(nums[i] == val)
            {
                nums[i--] = nums[len-- -1];
            }
        }
        return len;
    }
}

26.Remove Duplicates from Sorted Array

https://leetcode.com/problems/remove-duplicates-from-sorted-array/
有序数组去重,和前一题类似,虽然是嵌套循环,复杂度还是O(n)

public class Solution {
    public int removeDuplicates(int[] nums) {
        int len = nums.length;
        int dup = 0;
        for( int i = 0; i < len; )
        {
            int j = i+1;
            for(; j < len && nums[i] == nums[j]; j++)
            {
                dup++;
                continue;
            }
            i = j;
            nums[i - dup-1] = nums[i-1];
        }
        return len-dup;
    }
}

看了给出的方法,感觉自己秀逗了,既然是O(n)的方法,遍历的只是两个游标,可以改到一个循环中的,

public class Solution {
    public int removeDuplicates(int[] nums) {
       if(nums.length == 0)
            return 0;
       int j = 0;
       for(int i = 0; i < nums.length; i++)
            if(nums[i]!=nums[j])
                nums[++j] = nums[i];
        return ++j;
    }
}

80. Remove Duplicates from Sorted Array II

和上面一个很类似,但是多了一个两次的条件,在原代码基础上稍微改下,添加了个对是否为两次的标记,我是用int型的,其实用布尔型的也是一样的效果

public class Solution {
    public int removeDuplicates(int[] nums) {
        int j = 0;
        int dup = 0;
        for ( int i = 0; i < nums.length; i++)
        {
            if(nums[i] != nums[j])
            {
                nums[++j] = nums[i];
                dup = 0;
            }
            else if(dup == 0 && i!=j)//此处为了避免处理第一个元素时出问题,增加了一个i!=j的判断
            {
                dup = 1;
                nums[++j] = nums[i];
            }
        }
        return ++j;
    }
}

看了答案,提供了一个最多允许K个重复的方法,思路类似,不过是直接从下标为1的开始,赋值时先自增;比较时每个元素与前一个元素比较,更方便一些

public class Solution {
    public int removeDuplicates(int[] nums) {
        int n = nums.length;
        int k = 2;

        if( n <= k)
            return n;
        int i = 1, j = 1;
        int cnt = 1;
        while(i < n)
        {
            if(nums[i]!=nums[i-1])
            {
                cnt = 1;
                nums[j++] = nums[i];
            }
            else
            {
                if(cnt < k)
                {
                    nums[j++] = nums[i];
                    cnt++;
                }
            }
            i++;
        }
        return j;
    }
}

66. Plus One

https://leetcode.com/problems/plus-one/
用数组存的数字,返回+1之后的结果,涉及的是进位的考虑。

public class Solution {
    public int[] plusOne(int[] digits) {
        int carry = 1;
        int i = digits.length - 1;
        while( i >= 0)
        {
            int sum = digits[i] + carry;
            digits[i] = sum%10;
            carry = sum/10;
            if(carry == 0)
                return digits;
            i--;
        }
        int[] res = new int [digits.length+1];
        res[0] = carry;
        for(int j = 1; j < res.length; j++)
        {
            res[j] = 0;
        }
        return res;
    }
}

看了下参考的答案,针对的就是+1,所以是直接判断是否为9,不是的话+1返回,是的话该位变成0,有意思的一点是如果要增加一位数只需要对首位数赋为1,查了下Java中数组的用法, 确实可以

public class Solution {
    public int[] plusOne(int[] digits) {

    int n = digits.length;
    for(int i=n-1; i>=0; i--) {
        if(digits[i] < 9) {
            digits[i]++;
            return digits;
        }

        digits[i] = 0;
    }

    int[] newNumber = new int [n+1];
    newNumber[0] = 1;

    return newNumber;
}

118. Pascal’s Triangle

Java中List的初始化一般用ArrayList

public class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if(numRows<=0)
            return res;
        for(int i = 0; i < numRows; i++)
        {
            List<Integer> newRow = new ArrayList<Integer>();
            for(int j = 0; j <=i; j++)
            {
                if( j==0 || j == i)
                    newRow.add(1);
                else{
                    newRow.add(res.get(i-1).get(j-1)+res.get(i-1).get(j));
                }
            }
            res.add(newRow);
        }
        return res;
    }
}

119. Pascal’s Triangle II

https://leetcode.com/problems/pascals-triangle-ii/
和上题类似,但是要求只用O(k)的空间,因此需要一点小技巧,在赋值的时候从后面开始逐渐赋值

public class Solution {
    public List<Integer> getRow(int rowIndex) {
        List<Integer> res = new ArrayList<Integer>();
        for(int i = 0; i <= rowIndex; i++){
            res.add(1);//增加的操作放在内层循环外面会省事很多
            for(int j = i-1; j > 0; j--){
               res.set(j,res.get(j)+res.get(j-1));
            }
        }
        return res;
    }
}

与参考答案思路类似

2Sum

https://leetcode.com/problems/two-sum/
直接暴力解决,两层遍历解决,复杂度O(n^2)

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        for(int i = 0 ; i < nums.length; i++)
        {
            for(int j = i+1; j < nums.length; j++)
            {
                if(nums[i]+nums[j] == target)
                {
                    res[0] = i;
                    res[1] = j;
                }
            }
        }
        return res;
    }
}

写的时候就想O(n^2)的方法应该不是最优的,还有更好的,看了下参考答案确实是,思路也是常见的空间换时间,增加一个map结构的缓存,标记对应的数字是否出现过
话说回来,map结构真的很好用,改后的算法是O(n)时间O(n)空间

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
        for(int i = 0 ; i < nums.length; i++)
        {
            if(map.containsKey(target - nums[i]))
            {
                res[0] = map.get(target - nums[i]);
                res[1] = i;
                return res;
            }
            map.put(nums[i],i);
        }
        return res;
    }
}

3Sum

https://leetcode.com/problems/3sum/
想按照上题的思路,先写一个时间O(n^2)空间O(n)的方法,但发现有个问题没法解决,无法保证组合只出现一次,尝试用Set来写还是有问题。
目前的出错代码

public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        if(nums.length <= 2)
            return new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        Map<Integer,Integer> oneSum = new HashMap<Integer,Integer>();

        Set<List<Integer>> resSet = new HashSet<List<Integer>>();
        for(int i = 0; i < nums.length; i++)
        {
            oneSum.put(nums[i],i);
            for(int j = i+1; j < nums.length; j++)
            {
                if(oneSum.containsKey(0 - nums[i]-nums[j]))
                {
                    List<Integer> tmp = new ArrayList<Integer>();
                    tmp.add(0 - nums[i]-nums[j]);
                    tmp.add(nums[i]);
                    tmp.add(nums[j]);
                    resSet.add(tmp);
                }
            }
        }
        List<List<Integer>> res = new ArrayList<List<Integer>>(resSet);
        return res;
    }
}

参考了下Top Solutions,有意思的是其中做了对重复元素的跳过,保证了答案的唯一性。

public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        for(int i = 0; i < nums.length-2; i++)
        {
            if(i == 0 || (i > 0 && nums[i]!=nums[i-1]))
            {
                int low = i+1, high = nums.length-1, sum = 0 - nums[i];
                while(low < high)
                {
                    if(nums[low] + nums[high] == sum)
                    {
                        res.add(Arrays.asList(nums[i],nums[low],nums[high]));
                        while(low < high && nums[low] == nums[low+1])
                            low++;
                        while(low < high && nums[high] == nums[high-1])
                            high--;
                        low++;
                        high--;
                    }
                    else if(nums[low]+nums[high] < sum)
                        low++;
                    else
                        high--;
                }
            }
        }
        return res;
    }
}

考虑了下为什么不能在2Sum中用这种方法,一是需要排序,时间复杂度会变成O(nlogn),二是2Sum要求返回的是下标,那样就需要一个结构来存数据值与下标的映射关系,而且还要保证先后顺序,逻辑会比较复杂,就远不如那个O(n)的算法好用啦

3Sum Closest

https://leetcode.com/problems/3sum-closest/
和上题的思路差不多,而且因为是假设有唯一答案,返回值只是三者的和,也不需要对重复元素跳过

public class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int res = nums[0]+nums[1]+nums[2];
        for(int i = 0; i < nums.length-2; i++)
        {
            int low = i+1, high = nums.length -1;
            while(low < high)
            {
                int sum = nums[low]+nums[high]+nums[i];
                if (sum < target)
                {
                    low++;
                }
                else
                {
                    high--;
                }
                if(Math.abs(target - sum) < Math.abs(target - res))
                {
                    res = sum;
                }
            }
        }
        return res;
    }
}

Search a 2D Matrix

https://leetcode.com/problems/search-a-2d-matrix/
这个题目是在一个有序的矩阵里找指定元素,而且虽然是二维的,但是完全可以当作一维有序数组,第一眼看到题目,想用二分的想法,复杂度应该是O(log(mn))

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if(matrix == null || matrix.length == 0)
            return false;
        int row_num = matrix.length;
        int col_num = matrix[0].length;

        int begin = 0, end = row_num * col_num - 1;

        while(begin <= end){
            int mid = (begin + end) / 2;
            int mid_value = matrix[mid/col_num][mid%col_num];
            if( mid_value == target){
                return true;
            }else if(mid_value < target){
                begin = mid+1;
            }else{
                end = mid-1;
            }
        }
        return false;
    }
}

看了下参考资料,有一种看起来更简洁的方法,但复杂度是O(m+n),这种解法不仅适用于本题目,也适用于另外一道类似的题目

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if(matrix == null || matrix.length == 0)
            return false;
        int clen = matrix[0].length;
        int rlen = matrix.length;
        int rnum = 0, cnum = clen-1;
        while(rnum < rlen && cnum >= 0){
            if(matrix[rnum][cnum] > target)
                cnum--;
            else if(matrix[rnum][cnum] < target)
                rnum++;
            else
                return true;
        }
        return false;
    }
}

Find Peak Element

https://leetcode.com/problems/find-peak-element/
这道题目也可以用二分法来做,需要注意的地方在于边界条件的判断,如何保证数据不会溢出

public class Solution {
    public int findPeakElement(int[] nums) {
        int low = 0, high = nums.length -1;
        if(nums.length <= 1)
            return 0;
        while( low <= high){
            int mid = (low+high)>>1;
            if((mid==nums.length-1||nums[mid]>nums[mid+1])&&(mid==0||nums[mid]>nums[mid-1])){
                return mid;
            }
            else if(nums[mid] < nums[mid+1]){
                low = mid+1;
            }else{
                high = mid-1;
            }
        }
        return low;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值