每日一练(day10)

Posted 'or 1 or 不正经の泡泡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一练(day10)相关的知识,希望对你有一定的参考价值。

文章目录

警句

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

题目

只出现一次的数字

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

示例 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;
    


以上是关于每日一练(day10)的主要内容,如果未能解决你的问题,请参考以下文章

每日一练(day01)

每日一练(day09补08,03,04)

每日一练(day04)

每日一练(24):在排序数组中查找数字

每日一练(day11&look look Arrary.sort())

每日一练<4>