每日一练(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)的主要内容,如果未能解决你的问题,请参考以下文章