【leetcode刷题笔记(2)】

主题:数组

(1)1. 两数之和

法一:遍历
法二:利用哈希表存储剩余值和索引;

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

(2)4. 寻找两个正序数组的中位数(错1)

(3)11. 盛最多水的容器(错1)

题解:双指针

class Solution {
    public int maxArea(int[] height) {
        int max = 0;
        int area = 0;
        int i = 0;
        int j = height.length-1;
        while(i < j){
            if(height[i] < height[j]){
                area = (j-i) * height[i];
            }else{
                area = (j-i) * height[j];
            }
            if(area > max){
                max = area;
            }
            if(height[i] < height[j]){
                i++;
            }else{
                j--;
            }
        }
        return max;
    }
}

(4)15. 三数之和(错1)

题解思路:排序+双指针:先对数组进行排序,每层遍历的索引比前面的大,避免部分重复搜索;当当前搜索的数值与前一轮搜索的数值一样时,跳过当前前轮,进入下一轮搜索;当第一轮数值确定时,后面两个之和就确定了,对后面两个数字使用双指针分别从数组前后开始搜索。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int len = nums.length;
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<List<Integer>>();

        for(int first = 0; first < len;first++){
            if(first > 0 && nums[first] == nums[first - 1]){
                continue;
            }
            int third = len - 1;
            int target = - nums[first];

            for(int second = first + 1; second < len; second++){
                if(second > first + 1 && nums[second] == nums[second - 1]){
                    continue;
                }
                while(second < third && nums[second] + nums[third] > target){
                    third--;
                }
                if(second == third){
                    break;
                }
                if(nums[second] + nums[third] == target){
                    List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[first]);
                    list.add(nums[second]);
                    list.add(nums[third]);
                    res.add(list);
                }
            }
        }
        return res;
    }
}

(5)16. 最接近的三数之和

我的思路:与三数之和的方法一样,排序+双指针。
注意返回值的要求。

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int close = Math.abs(nums[0] + nums[1] + nums[2] - target);
        int res = nums[0] + nums[1] + nums[2];
        int len = nums.length;
        int temp;
        Arrays.sort(nums);
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        for(int first = 0; first < len;first++){
            if(first > 0 && nums[first] == nums[first-1]){
                continue;
            } 
            for(int second = first+1; second < len;second++){
                int third = len-1;
                if(second > first+1 && nums[second] == nums[second-1]){
                    continue;
                }
                while(third > second){
                    temp = Math.abs(nums[first] + nums[second] + nums[third] - target);
                    if(temp < close){
                        close = temp;
                        res = nums[first] + nums[second] + nums[third];
                    }
                    third--;
                }
            }
        }
        return res;
    }
}

(6)18. 四数之和

我的思路:在三数之和的基础上,加一层循环

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        int len = nums.length;
        if(len < 4){
            return res;
        }
        Arrays.sort(nums);
        for(int first = 0; first < len; first++){
            if(first > 0 && nums[first] == nums[first-1]){
                continue;
            }
            for(int second = first + 1; second < len; second++){
                if(second > first + 1 && nums[second] == nums[second-1]){
                    continue;
                }
                int fourth = len - 1;
                int aim = target - nums[first] - nums[second];
                for(int third = second+ 1; third < len; third++){
                    if(third > second+1 && nums[third] == nums[third-1]){
                        continue;
                    }
                    while(third < fourth && nums[third] + nums[fourth] > aim){
                        fourth--;
                    }
                    if(third == fourth){
                        break;
                    }
                    if(nums[third] + nums[fourth] == aim){
                        List<Integer> list = new ArrayList<Integer>();
                        list.add(nums[first]);
                        list.add(nums[second]);
                        list.add(nums[third]);
                        list.add(nums[fourth]);
                        res.add(list);
                    }
                }
            }
        }
        return res;
    }
}

(7)26. 删除有序数组中的重复项

我的思路:每找到一个重复项,调整后面的所有数据项再检查后面的数据。

class Solution {
    public int removeDuplicates(int[] nums) {
        int len = nums.length;
        if(len < 2){
            return len;
        }
        int pre = 0;
        int cur = 1;
        while(cur < len){
            int count = 0;
            while(cur < len && nums[pre] == nums[cur]){
                cur++;
                count++;
            } 
            for(int i = 1; cur-1+i < len; i++){
                nums[pre+i] = nums[cur-1+i];
            }
            len -= count;
            pre++;
            cur = pre + 1;
        }
        return len;
    }
}

题解:双指针法,在搜索的同时调整后面数据的位置,pre表示当前搜索完的位置,cur表示正在搜索检查的位置。不是检查一个调整一次,大大减小了时间复杂度。

class Solution {
    public int removeDuplicates(int[] nums) {
        int len = nums.length;
        if(len < 2){
            return len;
        }
        int pre = 0;
        int cur = 1;
        while(cur < len){
            if(nums[pre] == nums[cur]){
                cur++;
            }else{
                pre++;
                nums[pre] = nums[cur];
                cur++;
            }
        }
        return pre+1;
    }
}

(8)27. 移除元素

我的思路:双指针法,pre为当前检查完毕的位置,cur为正在检查的位置,在检查的过程中,同时调整数组。

class Solution {
    public int removeElement(int[] nums, int val) {
        if(nums.length == 0){
            return 0;
        }
        int pre = 0;
        int cur = 0;
        while(cur < nums.length){
            if(nums[cur] == val){
                cur++;
            }else{
                nums[pre] = nums[cur];
                pre++;
                cur++;
            }
        }
        return pre;
    }
}

题解其他思路:双指针优化,因为题目说元素的位置可以变化,从左右两边开始检查,if left = val,将right复制到left,right–,直到left != val,left++,当right=left时,检查完成。
注意:right从length处开始,检查位置为right-1,可以保证元素只有一个时,也能进入循环。

class Solution {
    public int removeElement(int[] nums, int val) {
        if(nums.length == 0){
            return 0;
        }
        int left = 0;
        int right = nums.length;
        while(left < right){
            if(nums[left] == val){
                nums[left] = nums[right-1];
                right--;
            }else{
                left++;
            }
        }
        return left;
    }
}

(9)31. 下一个排列(错1)

题解思路:两遍扫描;从后往前找到

class Solution {
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        if (i >= 0) {
            int j = nums.length - 1;
            while (j >= 0 && nums[i] >= nums[j]) {
                j--;
            }
            swap(nums, i, j);
        }
        reverse(nums, i + 1);
    }

    public void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    public void reverse(int[] nums, int start) {
        int left = start, right = nums.length - 1;
        while (left < right) {
            swap(nums, left, right);
            left++;
            right--;
        }
    }
}

(10)33. 搜索旋转排序数组

我的思路:先找到旋转位置,判断target在哪半边数组,再进行二分查找,

class Solution {
    public int search(int[] nums, int target) {
        if(nums == null){
            return -1;
        }
        if(nums.length == 1){
            if(nums[0] == target){
                return 0;
            }else{
                return -1;
            }
        }
        int pre = 0;
        int cur = 1;
        while(cur < nums.length && nums[pre] < nums[cur]){
            pre++;
            cur++;
        }
        if(target >= nums[0]){
            return binarySearch(nums,0,pre,target);
        }else{
            return binarySearch(nums,cur,nums.length-1,target);
        }
    }
    public static int binarySearch(int[] nums, int left,int right, int target){
        if(left <= right){
            int mid = (left + right) / 2;
            if(nums[mid] < target){
                return binarySearch(nums,mid+1,right,target);
            }else if(nums[mid] > target){
                return binarySearch(nums,left,mid-1,target);
            }else{
                return mid;
            }
        }
        return -1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值