剑指Offer面试题解总结61~70

剑指Offer61~70

和为s的两个数字

题链
题解:双指针问题,设两个指针l,r分别指向数组首尾,然后每次判断nums[l]+nums[r]是否大于target,如果大于则r–,r遍历完后l++.

 public int[] twoSum(int[] nums, int target) {
      int l = 0,r = nums.length-1;
      while(l < r){
         
          while(nums[l] + nums[r] > target){
              r--;
          }
           if(nums[l] + nums[r] ==  target){
              return new int[]{nums[l],nums[r]};
          }
          l++;
      }
      return new int[2];
  }

和为s的连续正数序列

题链
题解:双指针问题.设两个指针l,r每次记录sum=(l+r)(r-l+1)/2与target的大小,当sum==target则返回l~r,sum< target则r++,否则l++.

 public int[][] findContinuousSequence(int target) {
       List<int[]> list = new ArrayList<>();
        for(int l = 1,r = 2; l < r;){
            int sum = (l + r) * (r - l + 1) / 2;
            if(sum == target){
                int[] cur = new int[r - l + 1];
                for(int i = l;i <= r; i++){
                    cur[i-l] = i;
                }
                list.add(cur);
                l++;
            }else if(sum < target){
                r++;
            }else{
                l++;
            }
        }
        return list.toArray(new int[list.size()][]);
    }

翻转单词顺序

题链
题解:首先去掉原字符串的前后的多余空格,然后分别翻转每个单词,然后再翻转整个字符串.

public String reverseWords(String s) {
    if(s == null || s.length() == 0){
        return s;
    }
      String[] strs = s.split(" ");
        String ans = "";
        int n = strs.length;
        for(int i = n-1; i >= 0; i--){
            if("".equals(strs[i])){
                continue;
            }
            ans += strs[i] + " ";
        }
        if(ans.length() == 0){
            return ans;
        }
        return ans.substring(0,ans.length()-1);
    }
    public char[] reverse(char[] arr,int l,int r){
        while(l < r){
            char tmp = arr[l];
            arr[l] = arr[r];
            arr[r] = tmp;
            l++;
            r--;
        }
        return arr;
    }

左旋转字符串

题链
题解:与翻转字符串思路类似,以第k个字符作为分割分别翻转左侧和右侧的子字符串后再翻转整个字符串.还有一种骚操作:将两个字符串拼接起来,然后返回新字符串的第k位到第k+length位.

 public String reverseLeftWords(String s, int n) {
        String ans = s + s;
        int len = s.length();
        return ans.substring(n,n+len);
    }

滑动窗口的最大值

题链
题解:考察的是单调队列的应用.维护一个单调队列:队首为最大值.每次更新新元素时要保证队列的递减.同时在移除头部元素时要检验队首元素的下标是否应该被移除.

 public int[] maxSlidingWindow(int[] nums, int k) {
        Deque<Integer> q = new LinkedList<>();
        int n = nums.length;
        if(n == 0){
            return nums;
        }
        int[] ans = new int[n - k + 1];
        int index = 0;
        for(int i = 0; i < n; i++){
            while(!q.isEmpty() && nums[i] >= nums[q.peekLast()]){
                q.pollLast();
            }
            q.offerLast(i);
            if(i >= k - 1){
                ans[index++] = nums[q.peekFirst()];
                if(q.peekFirst() == i - k + 1){
                    q.pollFirst();
                }
            }
        }
        return ans;
    }

队列的最大值

题链
题解:维护两个队列,一个队列负责元素的进和出,一个队列负责表示当前队列中的最大元素.分别记为q和maxQ,在进元素时,q中直接进元素,maxQ进行一次判断:当maxQ为空或maxQ的队头元素小于等于进入元素时将元素放入队列中,否则先弹出maxQ的队头元素.在出元素时,q中直接出元素,maxQ中要判断出的元素是否等于maxQ的队头元素,如果等于将maxQ的队头元素也弹出.

 Deque<Integer> q;
    Deque<Integer> maxQ;
    public MaxQueue() {
        q = new LinkedList<>();
        maxQ = new LinkedList<>();
    }

    public int max_value() {
        if(q.size() == 0){
            return -1;
        }
        return maxQ.peekFirst();
    }

    public void push_back(int value) {
        q.offerLast(value);
        while(!maxQ.isEmpty() && value > maxQ.peekLast()){
            maxQ.pollLast();
        }
        maxQ.offerLast(value);
    }

    public int pop_front() {
        if(q.size() == 0){
            return -1;
        }
        if(maxQ.peekFirst().equals(q.peekFirst())){
            maxQ.pollFirst();
        }
        return q.pollFirst();
    }

n个骰子的点数

题链
题解:动态规划.记录f[i][j]为i个骰子向上和为j时的概率.那么f[i][j] = (f[i-1][j-1]+…+f[i-1][j-6])/6.

  public double[] dicesProbability(int n) {
        double[] dp = new double[6];
        Arrays.fill(dp,1.0/6);
        for(int i = 2; i <= n; i++){
            double[] cur = new double[5*i+1];
            for(int j = 0; j < dp.length; j++){
				//之所以正着推是为了避免多次讨论数组越界
                for(int k = 0; k < 6; k++){
                    cur[j+k] += dp[j] / 6.0;
                }
            }
            dp = cur;
        }
          return dp;
    }

扑克牌中的顺子

题链
题解:简单的模拟题.首先对数组排序,当数组中出现两个相同非0的数字时返回false.记录0出现的次数cnt和数组中非零的最大差sum-1-(3-cnt,比较两者的值,当前者大于等于后者时返回true.

 public boolean isStraight(int[] nums) {
        Arrays.sort(nums);
        for(int i = 0; i < 4; i++){
            if(nums[i] == nums[i+1] && nums[i] != 0){
                return false;
            }
        }
        if(isV(nums)){
            return true;
        }
        int cnt = 0;
        for(int i = 0; i < 5; i++){
            if(nums[i] == 0){
                cnt++;
            }
        }
        int sum = 0;
        sum = nums[4] - nums[cnt] -1-(3-cnt);
        return sum <= cnt;

    }
    public boolean isV(int[] nums){
        return (nums[0] + 1 == nums[1] && nums[1] + 1 == nums[2]
            && nums[2] + 1 == nums[3] && nums[3] + 1 == nums[4]);
    }

圆圈中最后剩下的数字

题链
题解:约瑟夫环.对于n个元素,第一个要删除的数是第m%n个,假设n-1个元素最终剩下的元素的编号是x,那么f[n] = (m%n+x) % n,因此可以通过迭代得到最终结果.

	 public int lastRemaining(int n, int m) {
		int a = 0;
		for(int i = 2; i <= n; i++){
			a = (m+a)%i;
		}
		return a;
    }

股票的最大利润

题链
题解:利用贪心去解决.首先定义一个当前天的最小价格minPrice和当前天得到的最大利润maxProfit.顺序遍历数组的每个元素,每次比较minPrice与当前元素的值,如果前者大于后者则用后者更细前者,否则判断当前天数-minPrince与maxProfit的大小,如果前者更大,则用前者更新后者.

 public int maxProfit(int[] prices) {
        int price = Integer.MAX_VALUE;
        int profit = 0;
        int len = prices.length;
        for(int i = 0; i < len; i++){
            if(prices[i] < price){
                price = prices[i];
            }else if(prices[i] - price > profit){
                profit = prices[i] - price;
            }
        }
        return profit;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

囚蕤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值