每日一练(day10)

141 阅读4分钟

@[TOC]

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。

警句

少而好学,如日出之阳;壮而好学,如日中之光;志而好学,如炳烛之光。——刘向

题目

只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 说明: 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 示例 1: 输入: [2,2,1] 输出: 1 示例 2: 输入: [4,1,2,1,2] 输出: 4

我第一反应就是直接使用hash来做,但是题目有说明,这样的话就不好了。能解题但是不是最优解。

于是我又想到了使用一个指针,一开始这个指针获取第一个数字,然后去扫描判断这个数字有没有重复的,如果有,这个指针代表的数字重置,然后再去判断下一个,知道扫描完毕,如果没有重复的那么指针指向的值为没有重复值,但是问题在于这个指针重置的值怎么设置,这个值不能是我们列表里面有的东西,所以,问题在这。

后来我想起来昨天用的位运算,没错直接用异或不就ok了。

class Solution {
    public int singleNumber(int[] nums) {
        int flag = 0;
        for (int num : nums) {
            flag ^= num;
        }
        return flag;
    }
}

移动0

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0]

这个是简单的双指针问题嘛

class Solution {
    public void moveZeroes(int[] nums) {
        for(int i=0,j=0;j<nums.length;j++){
            if(nums[j] !=0){
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                i++;
            }
        }
    }
}

机器人的运动范围【剑指offer13】

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子? 示例 1: 输入:m = 2, n = 3, k = 1 输出:3 示例 2: 输入:m = 3, n = 1, k = 0 输出:1

第一反应,看到机器人先想到的是DP,一个一个方格子走嘛。但是这边不仅仅是找那个路的走法,同时我们要找到 那个 x +y 坐标<=k 的,所以这里涉及到搜索问题。并且这里的x.y是坐标拆分之后相加 就像那个例子。

但是关于这个题目的话,问的是能够到达多少个格子,没说要走什么路,所以这里又变了,变成了一个迷宫问题,从0,0出发,上下左右,之和大于k的就是墙,并且我们需要的是所有的可以走的路,所以我们这边就可以使用BFS,当然也可以用DFS.但是这里要更简单,因为只是一个中档题,直接暴力搜索就可以,不需要像先前的问题一样

class Solution {
    public int movingCount(int m, int n, int k) {
        if (k == 0) {
            return 1;
        }
        boolean[][] juzheng = new boolean[m][n];
        int ans = 1;
        juzheng[0][0] = true;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if ((i == 0 && j == 0) || getsplitsum(i) + getsplitsum(j) > k) {
                    continue;
                }
                // 边界判断
                if (i - 1 >= 0) {
                    juzheng[i][j] |= juzheng[i - 1][j];
                }
                if (j - 1 >= 0) {
                    juzheng[i][j] |= juzheng[i][j - 1];
                }
                ans += juzheng[i][j] ? 1 : 0;
            }
        }
        return ans;
    }

    public int getsplitsum(int x) {
        int res = 0;
        while (x != 0) {
            res += x % 10;
            x /= 10;
        }
        return res;
    }
}

一维数组的动态求和

给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。

请返回 nums 的动态和。

示例 1:

输入:nums = [1,2,3,4] 输出:[1,3,6,10] 解释:动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4] 。

来换换脑子,来个弱智题。

class Solution {
    public int[] runningSum(int[] nums) {
        for(int i=1;i<nums.length;i++){
            nums[i] = nums[i]+nums[i-1];
        }
        return nums;
    }
}

剑指offer 63 滑动窗口的最大值

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。 示例: 输入: nums = [1,3,-1,-3,5,3,6,7] , 和 k = 3 输出: [3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7]

这个乍一看,好像很简单,很快我们就想到了思路,于是我们这样做

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        List<Integer> flag = new ArrayList<>();
        for(int i=0;i<nums.length;i++){
            if(i+k-1>=nums.length){

                break;
            }else {
                flag.add(max(nums,i,i+k-1));
            }

        }
        return flag.stream().mapToInt(Integer::intValue).toArray();
    }

    public int max(int[] nums,int left,int right){
        int max = nums[left];
        for(int i=left;i<=right;i++){
            if(max<nums[i]){
                max = nums[i];
            }
        }
        return max;
    }
}

于是我们取得了这样的战绩 在这里插入图片描述 所以我们这边其实还涉及到优化的问题。

优化

前面是我们从左到右扫描了一遍,同时每次扫描一遍我们都需要求最大值,所以这个复杂度直接飙升,就是个暴力解法。但是我们其实发现我们在窗口滑动的过程当中发现,一个数字可以在A窗口也可以在B窗口,如果我们假设有个数字3是A窗口的最大值,并且3在B窗口,由于是从左到右滑动,所以我们其实只需要比较3后面的数字大不大(在B窗口当中)也就是说,如果在当前添加的元素当中的值,比上一个滑动窗口的最大值还小,那就不需要再比较了(两个窗口的交集中)此外这里优化了一下那个返回值的长度,先前是直接使用arrary然后转化消耗贼大

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length==0)
            {
                return new int[0];
            }
        int[] res=new int[nums.length-k+1];
        res[0]=Integer.MIN_VALUE;
        for(int j=0;j<k;j++){
            res[0]=Math.max(res[0],nums[j]);
        }
        for(int i=1;i<res.length;i++){
            if(nums[i+k-1]>=res[i-1])
                res[i]=nums[i+k-1];
            else
            {
                if(nums[i-1]!=res[i-1]){
                    res[i]=res[i-1];
                }
                else{
                    res[i]=Integer.MIN_VALUE;
                    for(int j=i;j<k+i;j++){
                        res[i]=Math.max(res[i],nums[j]);
                    }

                }
            }
        }
        return res;
    }
}

在这里插入图片描述