当前位置:   article > 正文

LeetCode面试经典150_leetcode面试经典 150 题

leetcode面试经典 150 题


~~堆点思路屎在这里
https://leetcode.cn/studyplan/top-interview-150/

189. 轮转数组

第一反应是创建一个额外数组,把后k位数组拿走放到前面来

class Solution{
    public void rotate(int[] nums, int k){
        //新建数组储存k位,进行移动
        int n = nums.length;
        k %= n;
        int[] temp = new int[k];
        System.arraycopy(nums, n - k, temp, 0, k);
        for (int i = n-k-1; i >= 0; i--) nums[i+k] = nums[i];
        System.arraycopy(temp, 0, nums, 0, k);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

看了题解才发现另一个写法是环状替换,将每个数字向右移动k位,从而达到整个移动的效果
在这里插入图片描述
//图片源于官方题解

官方题解提到的对于数学推导理解一定困难的解决方法

将第i位赋值给(i+k)%n位,并将(i+k)%n位赋值给((i+k)+k)%n位……,重复上述的操作直到赋值位回到第i位,若遍历的数字数量达到了n个,则代表遍历结束,反之则让i+1,继续遍历
请添加图片描述
先执行判断count数量操作,再执行start++操作,否则当nums.length为1时会出现数组越界问题

class Solution {
    public void rotate(int[] nums, int k) {
        //环状替换
        int n = nums.length;
        int count = 0, start = 0, temp = nums[start], i,  t; //temp储存被替换的数, t储存交换的数, i储存当前位置, count储存交换的次数, start储存起始位置
        k %= n;
        i = start;
        while (count < n) {
            i = (i + k) % n;
            //交换temp和nums[(start+k)%n]
            t = nums[i];
            nums[i] = temp;
            temp = t;
            count++;
            if (count == n) break;
            //判断是否回到原点,判断是否已经交换了n个数
            if (i == start) {
                start++;
                i = start;
                temp = nums[start];
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

121. 买卖股票的最佳时机

简单的题目,设置minn,maxn,ans三个变量,如果有更低的价格则更新ans和minn,如果有更高的价格则更新maxn和ans

class Solution {
    public int maxProfit(int[] prices) {
        int maxn, minn, ans = 0;
        maxn = minn = prices[0];
        for (int i = 1; i < prices.length; i++){
            if (prices[i] < minn) {
                ans = Math.max(ans, maxn - minn);
                minn = maxn = prices[i];
            }
            if (prices[i] > maxn) {
                maxn = prices[i];
                ans = Math.max(ans, maxn - minn);
            }
        }
        return ans;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

122. 买卖股票的最佳时机 II

如果价格起伏很大,那么一直持有划算还是购买并买入划算呢? 这里假设操作为买、卖、空三种操作代表买入、卖出和不操作
如价格波动为1536,那么买卖买卖的利润为7,买空空卖的利润为5

易观察到:只要前一天的价格比后一天的高,那么先卖出再买入的利润一定高于持有不卖的利润
那么我们的购买策略应该是这样的

  1. 如果明天的价格上涨了,我们会选择在今天买入,明天再卖出
  2. 如果明天的价格下跌了,我们不会进行操作(买明天的股票优于现在买股票)
  3. 我们也不用考虑最后一天股票用不用卖出的问题了,只在有利润的时候我们才会买彩票
class Solution {
    public int maxProfit(int[] prices) {
        int profit = 0;
        for (int i = 0; i < prices.length - 1; i++)
            if (prices[i+1] > prices[i]) profit += prices[i+1] - prices[i];
        return profit;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

55. 跳跃游戏

简单的动态规划问题,建立一个长度为nums.length的boolean数组,除了0之外其他的值都为false
从0开始遍历,能到达的位置设为true

class Solution {
    public boolean canJump(int[] nums) {
        boolean judge[] = new boolean[nums.length];
        judge[0] = true;
        for (int i = 0; i < nums.length; i++)
            if (judge[i])
                for (int j = 1; j <= nums[i]; j++)
                    if (i + j < nums.length) judge[i + j] = true;
        return judge[nums.length - 1];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后发现运行时间过于长了,代码的时间复杂度是 O ( n 2 ) O(n^2) O(n2) 其中 n 是数组 nums 的长度。这是因为使用了两个嵌套的循环。外层循环遍历数组中的每个元素,内层循环根据当前位置能够跳跃的步数,更新布尔数组 judge。
可以只用一个变量来表示可以到达的长度,这样也能够代表跳跃的长度

class Solution {
    public boolean canJump(int[] nums) {
        int k = 0;
        for (int i = 0; i < nums.length; i++){
            if (i > k) return false;
            k = Math.max(k, i + nums[i]);
        }
        return true;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

45. 跳跃游戏 II

怪不得刚刚控制不住自己建了一个boolean数组,原来是写过这道题
简单的动态规划问题,建立一个长度为nums.length的数组
从0开始遍历,能到达的位置更新最小跳跃数为当前位置+1

class Solution {
    public int jump(int[] nums) {
        int minn[] = new int[nums.length];
        minn[0] = 1;//等等结果再减一,为了防止0的情况
        for (int i = 0; i < nums.length; i++) {
            if (minn[i]==0 || nums[i]==0) continue;
            for (int j = 1; j <= nums[i]; j++) {
                if (i+j >= nums.length) break;
                if (minn[i+j] == 0) minn[i+j] = minn[i] + 1;
                else minn[i+j] = Math.min(minn[i+j], minn[i] + 1);
            }
        }
        return minn[nums.length-1]-1;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

然后发现运行时间过于长了,看了题解才知道可以在一次循环中解决,其思路是:

  1. 对于第一次跳跃,记录当前跳跃的最远距离
  2. 位置当前跳跃的最远距离时,记录所有位置能到达的新的最远距离
  3. 位置超过了当前跳跃的最远距离,将新的最远距离设为当前跳跃的最远距离,且跳跃次数+1
class Solution {
    public int jump(int[] nums) {
        int curDis = 0,jump = 0, maxDis = 0;
        for (int i = 0; i < nums.length - 1; i++){//最后一个元素不用跳
            maxDis = Math.max(maxDis, i + nums[i]);
            if (i == curDis) {
                jump++;
                curDis = maxDis;
            }
        }
        return jump;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

274. H指数

思路是排序后二分查找

class Solution {
    public int hIndex(int[] citations) {
        //排序citations
        int n = citations.length;
        Arrays.sort(citations);
        //二分查找
        int l = 0, r = n - 1, mid;
        while (l <= r){
            mid = (l+r) / 2;
            if (citations[mid]==n-mid) return n-mid;
            else if (citations[mid]>n-mid) r = mid - 1;
            else l = mid + 1;
        }
        return n-l;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

上面的复杂度是 O ( n l o g ( n ) ) O(nlog(n)) O<

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/1017567
推荐阅读
相关标签
  

闽ICP备14008679号