leetcode

1.二分查找

1.给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。题目链接

class Solution {
    public int searchInsert(int[] nums, int target){
        int l=0, r=nums.length-1;
        int mid = (l+r)>>>1;
        while(l<=r){
            if(target>nums[mid]){
                l = mid + 1;
            } else if(target == nums[mid]){
                return mid;
            } else{
                r = mid - 1;
            }
            mid = (l+r)>>>1;
        }
        return l;
    }
}

2.给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。题目链接

class Solution {
    public int mySqrt(int x) {
        if (x == 0) {
            return 0;
        }
        if (x < 4) {
            return 1;
        }
        //返回的结果:mid^2 <= x
        //返回结果的范围: 0-x
        int left = 2;
        int right = x / 2;
        int mid = left + (right - left + 1) / 2;
        while (left < right) {
            if (mid > x / mid) {
                right = mid - 1;
            } else {
                left = mid;
            }
            mid = left + (right - left + 1) / 2;
        }
        return left;
    }
}

3.给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n]这个范围内没有出现在数组中的那个数。题目链接

class Solution {
    public int missingNumber(int[] nums) {
        //方法一  亦或
        //1 xor 1 xor 2 xor 2跟1 xor 2 xor2 xor 1的结果没区别!
        //只要是同一组数,顺序异或跟乱序异或的结果是一样的!
        //任何数与0亦或都是它本身
        int[] res = new int[nums.length * 2 + 1]; 
        for (int i = 0; i < nums.length; i++) {
            res[i] = nums[i];
        }
        for (int i = 0; i < nums.length + 1; i++) {
            res[i + nums.length] = i;
        }
        int xor = 0;
        for (int i = 0; i < res.length; i++) {
            xor = xor ^ res[i];
        }
        return xor;

        //方法二 先排序
         Arrays.sort(nums);
         for (int i = 0; i < nums.length; i++) {
             if (i != nums[i]) {
                 return i;
             }
         }
         return nums.length;
    }
}

4.你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。题目链接

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left = 1;
        int right = n;
        int mid = (left + right) >>> 1;
        while(left < right){
            if(isBadVersion(mid)){
                right = mid;
            } else {
                left = mid + 1;
            }
            mid = (left + right) >>> 1;
        }
        return left;
    }
}

5.给定两个数组 nums1 和 nums2 ,返回它们的交集。输出结果中的每个元素一定是唯一的。我们可以不考虑输出结果的顺序 。题目链接

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        //方法一
        Set<Integer> set = new LinkedHashSet<>();
        //1. 两个数组排好序
        Arrays.sort(nums1);
        Arrays.sort(nums2);

        int i = 0;
        int j = 0;
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] == nums2[j]) {
                set.add(nums1[i]);
                i++;
                j++;
            } else if (nums1[i] < nums2[j]) {
                i++;
            } else {
                j++;
            }
        }
        int[] rs = new int[set.size()];
        int index = 0;
        for (Integer s : set) {
            rs[index++] = s;
        }
        return rs;

        //方法二
        List<Integer> arr = new ArrayList<>();
        //1. 两个数组排好序
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        //2. 遍历第二个数组
        for (int i = 0; i < nums2.length; i++) {
            //2.1 对第一个数组进行二分查找
            int left = 0;
            int right = nums1.length - 1;
            int mid = (left + right) >>> 1;
            while (left <= right) {
                if (nums2[i] < nums1[mid]) {
                    right = right - 1;
                } else if (nums2[i] == nums1[mid]) {
                    arr.add(nums1[mid]);
                    break;
                } else {
                    left = mid + 1;
                }
                mid = (left + right) >>> 1;
            }
            //2.2 判断当前元素值是否和下一个元素值相同,相同跳过下一个元素。
            while (i < (nums2.length - 1) && nums2[i] == nums2[i + 1]  ) {
                i++;
            }
        }
        int[] rs = new int[arr.size()];
        int j = 0;
        for (Integer a : arr) {
            rs[j] = a;
            j++;
        }
        return rs;
    }
}

6.两个数组的交集 II 给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);

        List<Integer> arr = new ArrayList<>();
        int i = 0;
        int j = 0;
        while(i<nums1.length && j<nums2.length){
            if(nums1[i] == nums2[j]){
                arr.add(nums2[j]);
                i++;
                j++;
            }else if(nums1[i] < nums2[j]){
                i++;
            } else{
                j++;
            }
        }
        int[] rs = new int[arr.size()];
        i = 0;
        for(int a : arr){
            rs[i++] = a;
        }
        return rs;
    }
}

7.有效的完全平方数给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

进阶:不要使用任何内置的库函数,如sqrt 。

class Solution {
    public boolean isPerfectSquare(int num) {
        if(num == 0 || num == 1){
            return true;
        }
        int left = 2;
        int right = num/2;
        int mid = (left + right) >>> 1;
        while(left <= right){
            if((long) mid * mid > num){
                right = mid - 1;
            } else if((long) mid * mid == num){
                return true;
            } else{
                left = mid + 1;
            }
            mid = (left + right) >>> 1;
        }
        return false;
    }
}

8.猜数字大小猜数字游戏的规则如下:

每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):

-1:我选出的数字比你猜的数字小 pick < num
1:我选出的数字比你猜的数字大 pick > num
0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num
返回我选出的数字。

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int left = 1;
        int right = n;
        int mid = (left + right) >>> 1;
        while(left < right){
            if(guess(mid) == -1){
                right = mid - 1;
            } else if(guess(mid) == 0){
                return mid;
            } else{
                left = mid + 1;
            }
            mid = (left + right) >>> 1;
        }
        return mid;
    }
}

9.排列硬币你总共有 n 枚硬币,并计划将它们按阶梯状排列。对于一个由 k 行组成的阶梯,其第 i 行必须正好有 i 枚硬币。阶梯的最后一行可能是不完整的。给你一个数字 n ,计算并返回可形成 完整阶梯行的总行数。

class Solution {
    public int arrangeCoins(int n) {
        //方法一
        if(n == 0) return 0;
        if(n == 1 || n == 2) return 1;
        long sum = 0;
        int i = 1;
        while(sum < n){
            sum += i++;
        }
        if(sum == n){
            return --i;
        } else{
            return i - 2;
        }

        //方法二
        long left = 1;
        long right = n;
        long mid = (left + right) >>> 1;
        long cur = 0;
        while(left <= right){
            cur = (mid+1)*mid/2;
            if(cur == n){
                return (int)mid;
            } else if(cur > n){
                right = mid - 1;
            } else{
                left = mid + 1;
            }
            mid = (left + right) >>> 1;
        }
        return (int)right;
    }
}

10.二分查找给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int mid = (left + right) >>> 1;  //int mid = left + (right - left)/2 
        while(left <= right){
            if(nums[mid] > target){
                right = mid - 1;
            } else if(nums[mid] == target){
                return mid;
            } else{
                left = left + 1;
            }
            mid = (left + right) >>> 1;
        }
        return -1;
    }
}

2.数组

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        //方法一
        int[] rs = new int[2];
        for(int i = 0; i < nums.length - 1; i++){
            for(int j = i + 1; j < nums.length; j++){
                if(nums[i] + nums[j] == target){
                    rs[0] = i;
                    rs[1] = j;
                    break;
                }
            }
        }
        return rs;
		
        //方法二
        Map<Integer, Integer> hasMap = new HashMap<>(nums.length-1);
        hasMap.put(nums[0],0);
        for(int i=1; i<nums.length; i++){
            if(hasMap.containsKey(target-nums[i])){
                return new int[]{hasMap.get(target-nums[i]),i};
            }
            hasMap.put(nums[i],i);
        } 
        throw new IllegalArgumentException("No two sum solution");
    }
}
26. 删除有序数组中的重复项

给你一个升序排列的数组 nums ,请你原地删除重复出现的元素,使每个元素只出现一次 ,返回删除后数组的新长度。元素的相对顺序应该保持一致 。

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么nums的前 k 个元素应该保存最终结果。

将最终结果插入nums的前 k 个位置后返回 k 。

不要使用额外的空间,你必须在 原地 修改输入数组并在使用 O(1) 额外空间的条件下完成。

class Solution {
    public int removeDuplicates(int[] nums) {
        //方法一
        int i = 0;
        int k = 1;
        int j = 0;
        while(i<nums.length - 1){
            for(j = i + 1; j<nums.length;j++){
                if(nums[i] == nums[j]){
                    continue;
                }
                i = j;
                nums[k++] = nums[j];
                break;
            }
            if(j >= nums.length){
                i++;
            }
        }
        return k--;

        //方法二
        int slow = 0;
        for(int fast = 1; fast < nums.length; fast++){
            if(nums[slow] != nums[fast]){
                nums[++slow]=nums[fast];
            }
        }
        return slow+1;
    }
}
27. 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

class Solution {
    public int removeElement(int[] nums, int val) {
        int k = 0;
        for(int i = 0; i<nums.length; i++){
            if(nums[i] != val){
                nums[k++] = nums[i];
            }
        }
        return k;
    }
}
35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

class Solution {
    public int searchInsert(int[] nums, int target){
        int l=0, r=nums.length-1;
        int mid = (l+r)>>>1;
        while(l<=r){
            if(target>nums[mid]){
                l = mid + 1;
            } else if(target == nums[mid]){
                return mid;
            } else{
                r = mid - 1;
            }
            mid = (l+r)>>>1;
        }
        return l;
    }
}
53. 最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

class Solution {
    public int maxSubArray(int[] nums) {
        long sum;
        long maxnum = nums[0];
        for(int i = 0; i < nums.length; i++){
            sum = 0;
            for(int j = i; j < nums.length; j++){
                sum += nums[j];
                maxnum = Math.max(sum,maxnum);
            }
        }
        return (int)maxnum;

        //动态规划
        int tempMax = nums[0];
        int max = nums[0];

        for(int i = 1; i < nums.length; i++){
            tempMax = Math.max(tempMax + nums[i], nums[i]);
            max = Math.max(max,tempMax);
        }
        return max;
    }
}
66. 加一

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

class Solution {
    public int[] plusOne(int[] digits) {
        for(int i=digits.length-1;i>=0;i--){
            if(digits[i]!=9){
                digits[i]++;
                break;
            }else{
                digits[i] = 0;
                if(digits[0]==0){
                    digits = new int[digits.length+1];
                    digits[0] = 1;
                    break;
                }
            }
        }
        return digits;
    }
}
118. 杨辉三角
class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> out = new ArrayList<List<Integer>>();
        for (int i = 0; i < numRows; i++) {
            List<Integer> arr = new ArrayList<Integer>();
            for (int j = 0; j < i + 1; j++) {
                if (i == 0) { // 第一层
                    arr.add(1);
                } else if (j == 0 || j == i){ // 第二层 + 下面层的最外面的两个数字
                    arr.add(1);
                } else {
                    List<Integer> tmp = out.get(i - 1);
                    arr.add(tmp.get(j - 1) + tmp.get(j)); // 计算
                }
            }
            out.add(arr);
        }
        return out;
    }
}
88. 合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你合并 nums2 到 nums1 中,使合并后的数组同样按非递减顺序排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
    //    int m2 = m;
    //    int k = 0;
    //    for(;m<nums1.length;m++){
    //        nums1[m] = nums2[k++];
    //    }
    //    if(m != m2){
    //       Arrays.sort(nums1);
    //    } 
        int lastIndex = nums1.length - 1;
        int i = m - 1;
        int j = n - 1;
        while(i>= 0 && j>=0){
            if(nums1[i] > nums2[j]) nums1[lastIndex--] = nums1[i--];
            else nums1[lastIndex--] = nums2[j--];
        }

        while(j>=0){
            nums1[lastIndex--] = nums2[j--];
        }
    }
}
118. 杨辉三角

给定一个非负整数 *numRows,*生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> out = new ArrayList<List<Integer>>();
        for (int i = 0; i < numRows; i++) {
            List<Integer> arr = new ArrayList<Integer>();
            for (int j = 0; j < i + 1; j++) {
                if (i == 0) { // 第一层
                    arr.add(1);
                } else if (j == 0 || j == i){ // 第二层 + 下面层的最外面的两个数字
                    arr.add(1);
                } else {
                    List<Integer> tmp = out.get(i - 1);
                    arr.add(tmp.get(j - 1) + tmp.get(j)); // 计算
                }
            }
            out.add(arr);
        }
        return out;
    }
}
119. 杨辉三角 II

给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

class Solution {
    public List<Integer> getRow(int rowIndex) {
        List<List<Integer>> out = new ArrayList<List<Integer>>();
        for (int i = 0; i <= rowIndex; i++) {
            List<Integer> arr = new ArrayList<Integer>();
            for (int j = 0; j < i + 1; j++) {
                if (i == 0) { // 第一层
                    arr.add(1);
                } else if (j == 0 || j == i){ // 第二层 + 下面层的最外面的两个数字
                    arr.add(1);
                } else {
                    List<Integer> tmp = out.get(i - 1);
                    arr.add(tmp.get(j - 1) + tmp.get(j)); // 计算
                }
            }
            out.add(arr);
        }
        return out.get(rowIndex);
    }
}
121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

class Solution {
    public int maxProfit(int[] prices) {
        int minPrice = prices[0];
        int max = 0;
        for (int i = 1; i < prices.length; i++) {
            max = Math.max(max, prices[i] - minPrice);
            minPrice = Math.min(minPrice, prices[i]);
        }
        return max;
    }
}
136. 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

class Solution {
    public int singleNumber(int[] nums) {
        for(int i = 1; i < nums.length; i++ ){
            nums[0] = nums[i]^nums[0];
        }
        return nums[0];
    }
}
169. 多数元素

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

class Solution {
    public int majorityElement(int[] nums) {
        //自己
        Map<Integer,Integer> maps = new HashMap<>();
        int num = 0;
        int rs = 0;
        for(int i = 0; i < nums.length; i++){
            maps.put(nums[i],0);
        }
        for(int i = 0 ; i < nums.length; i++){
            maps.put(nums[i], maps.get(nums[i])+1);
            if(maps.get(nums[i]) > num){
                num = maps.get(nums[i]);
                rs = nums[i];
            }
        }
        return rs;

        //方法二
        int rs = 0;
        int count = 0;
        for(int i = 0; i < nums.length; i++){
            if(count == 0) rs = nums[i];
            if(nums[i] == rs) count++;
            else count--;
        }
        return rs;
    }
}
219. 存在重复元素 II

给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false 。

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        //方法一
       for(int i = 0; i < nums.length; i++){
           for(int j = i + 1; j <= i + k && j < nums.length; j++){
               if(nums[i] == nums[j] && Math.abs(i-j)<=k){
                   return true;
               }
           }
       }
       return false;
        //方法二
        Map<Integer, Integer> maps = new HashMap<>();
        for(int i = 0; i < nums.length; i++){
            if(maps.containsKey(nums[i]) && (i - maps.get(nums[i]) <= k)) return true;
            maps.put(nums[i],i);
        }
        return false;
    }
}
228. 汇总区间

给定一个 无重复元素 的 有序 整数数组 nums 。

返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。

class Solution {
    public List<String> summaryRanges(int[] nums) {
        //方法一
        List<String> list = new ArrayList<>();
        String rs = "";
        String start = "";
        boolean flag = true;
        if(nums.length == 1){
            list.add("" + nums[0]);
            return list;
        }
        for(int i = 0; i < nums.length - 1; i++){
            if(nums[i] + 1 == nums[i+1]){
                if(flag){
                    start = nums[i] + "";
                    flag = false;
                    if(i == nums.length - 2){
                    rs = start + "->" + nums[i+1];
                    list.add(rs);
                    return list;
                    } 
                }
                if(i == nums.length - 2){
                    rs = start + "->" + nums[i+1];
                    list.add(rs);
                    return list;
                }
                continue;
            }
            if(flag){
                rs = start + nums[i];
            }else{
                rs = start + "->" + nums[i]; 
            }
            list.add(rs);
            flag = true;
            rs = "";
            start = "";
            if(i == nums.length - 2){list.add("" + nums[i+1]);}
        }
        return list;

        //方法二
         List<String> res = new ArrayList<>();
        // i 初始指向第 1 个区间的起始位置
        int i = 0;
        for (int j = 0; j < nums.length; j++) {
            // j 向后遍历,直到不满足连续递增(即 nums[j] + 1 != nums[j + 1])
            // 或者 j 达到数组边界,则当前连续递增区间 [i, j] 遍历完毕,将其写入结果列表。
            if (j + 1 == nums.length || nums[j] + 1 != nums[j + 1]) {
                // 将当前区间 [i, j] 写入结果列表
                StringBuilder sb = new StringBuilder();
                sb.append(nums[i]);
                if (i != j) {
                    sb.append("->").append(nums[j]);
                }
                res.add(sb.toString());
                // 将 i 指向更新为 j + 1,作为下一个区间的起始位置
                i = j + 1;
            }
        }
        return res;
    }
}
283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

class Solution {
    public void moveZeroes(int[] nums) {
        int index = 0;
        //遍历整个数组
        for(int i = 0; i < nums.length; i++){
            //寻找不为0的元素
            if(nums[i] != 0){
                int temp = nums[index]; 
                nums[index++] = nums[i];
                nums[i] = temp;
            }
        }
    }
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值