赞
踩
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
示例 1:
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
示例 2:
输入:n = 2
输出:false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/happy-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
通过例子我们会发现,如果之前出现的数字之后计算又出现了,说明肯定不是快乐数
例如:2——>4——>16——>37——>58——>89——>145——>42——>20——>4
⬆_____________________________________________________⬇
我们发现什么?变环了! 解决环形问题应该怎么做?大声告诉我!双指针!!!!
具体思路:
代码实现
public boolean isHappy(int n) { int fast=n; int slow=n; do{ slow=squareSum(slow); fast=squareSum(fast); fast=squareSum(fast); }while(slow!=fast); if(fast==1) return true; else return false; } private int squareSum(int m){ int squaresum=0; while(m!=0){ squaresum+=(m%10)*(m%10); m/=10; } return squaresum; }
给定两个人的空闲时间表:slots1 和 slots2,以及会议的预计持续时间 duration,请你为他们安排 时间段最早 且合适的会议时间。
如果没有满足要求的会议时间,就请返回一个 空数组。
「空闲时间」的格式是 [start, end],由开始时间 start 和结束时间 end 组成,表示从 start 开始,到 end 结束。
题目保证数据有效:同一个人的空闲时间不会出现交叠的情况,也就是说,对于同一个人的两个空闲时间 [start1, end1] 和 [start2, end2],要么 start1 > end2,要么 start2 > end1。
示例 1:
输入:slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 8
输出:[60,68]
示例 2:
输入:slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 12
输出:[]
思路:
ps:注意要先排序
代码实现:
class Solution { public List<Integer> minAvailableDuration(int[][] slots1, int[][] slots2, int duration) { Arrays.sort(slots1, (o1, o2) -> o1[0] - o2[0]);//排序 Arrays.sort(slots2, (o1, o2) -> o1[0] - o2[0]);//排序 List<Integer> res = new ArrayList<>(); int s1 = slots1.length; int s2 = slots2.length; int start1 = 0;//指针1 int start2 = 0;//指针2 while (start1 < s1 && start2 < s2) {//结束条件 int start = Math.max(slots2[start2][0], slots1[start1][0]); int cha = Math.min(slots2[start2][1], slots1[start1][1]) - start;//计算交集时间 if (cha >= duration) {//看是否满足条件 res.add(start); res.add(start + duration); //找到就退出,这样就满足了时间段最早这个条件 break; } else {//不满足条件 if (slots1[start1][1] < slots2[start2][1]) {//如果是第一个人的时间没赶上第二个人的时间 start1++; continue; } else if (slots2[start2][1] < slots1[start1][1]) {//如果是第二个人的时间没赶上第一个人的时间 start2++; continue; } else { start1++; start2++; } } } return res; } }
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
示例 2:
输入:nums = [3,1,3,4,2]
输出:3
思路:
实际上这个跟快乐数是一样的,快慢针就行了。
代码实现:
class Solution { public int findDuplicate(int[] nums) { int fast = 0, slow = 0; while(true) { fast = nums[nums[fast]]; slow = nums[slow]; if(slow == fast) { fast = 0; while(nums[slow] != nums[fast]) { fast = nums[fast]; slow = nums[slow]; } return nums[slow]; } } } }
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
思路:
起先思路就是我左边找个最大的,右边找个最大的,然后我计算当前这个位置存储的雨水量,如此一来就能求出总的雨水量了。但是这个思路的复杂度很高。因为我从左往右遍历的同时还要左右分别遍历求取最高值,时间复杂度为O(n²)。
class Solution { public int trap(int[] height) { int len = height.length; if (len == 0) { return 0; } int[] leftMax = new int[len]; leftMax[0] = height[0]; for (int i = 1; i < len; ++i) { leftMax[i] = Math.max(leftMax[i - 1], height[i]); } int[] rightMax = new int[len]; rightMax[len - 1] = height[len - 1]; for (int i = len - 2; i >= 0; --i) { rightMax[i] = Math.max(rightMax[i + 1], height[i]); } int ans = 0; for (int i = 0; i < len; ++i) { ans += Math.min(leftMax[i], rightMax[i]) - height[i]; } return ans; } }
行程编码(Run-length encoding)是一种压缩算法,能让一个含有许多段连续重复数字的整数类型数组 nums 以一个(通常更小的)二维数组 encoded 表示。每个 encoded[i] = [vali, freqi] 表示 nums 中第 i 段重复数字,其中 vali 是该段重复数字,重复了 freqi 次。
例如, nums = [1,1,1,2,2,2,2,2] 可表示称行程编码数组 encoded = [[1,3],[2,5]] 。对此数组的另一种读法是“三个 1 ,后面有五个 2 ”。
两个行程编码数组 encoded1 和 encoded2 的积可以按下列步骤计算:
将 encoded1 和 encoded2 分别扩展成完整数组 nums1 和 nums2 。
创建一个新的数组 prodNums ,长度为 nums1.length 并设 prodNums[i] = nums1[i] * nums2[i] 。
将 prodNums 压缩成一个行程编码数组并返回之。
给定两个行程编码数组 encoded1 和 encoded2 ,分别表示完整数组 nums1 和 nums2 。nums1 和 nums2 的长度相同。 每一个 encoded1[i] = [vali, freqi] 表示 nums1 中的第 i 段,每一个 encoded2[j] = [valj, freqj] 表示 nums2 中的第 j 段。
返回 encoded1 和 encoded2 的乘积。
注:行程编码数组需压缩成可能的最小长度。
示例 1:
输入: encoded1 = [[1,3],[2,3]], encoded2 = [[6,3],[3,3]]
输出: [[6,6]]
解释n: encoded1 扩展为 [1,1,1,2,2,2] ,encoded2 扩展为 [6,6,6,3,3,3]。
prodNums = [6,6,6,6,6,6],压缩成行程编码数组 [[6,6]]。
示例 2:
输入: encoded1 = [[1,3],[2,1],[3,2]], encoded2 = [[2,3],[3,3]]
输出: [[2,3],[6,1],[9,2]]
解释: encoded1 扩展为 [1,1,1,2,3,3] ,encoded2 扩展为 [2,2,2,3,3,3]。
prodNums = [2,2,2,6,9,9],压缩成行程编码数组 [[2,3],[6,1],[9,2]]。
思路:
这题还是挺简单的,双指针遍历呗,一个遍历encoded1,一个遍历encoded2。遍历的同时将结果add进res中。
细节:
代码实现:
class Solution { List<List<Integer>> res = new ArrayList<>(); public List<List<Integer>> findRLEArray(int[][] encoded1, int[][] encoded2) { int i = 0, j = 0; int len1 = encoded1.length, len2 = encoded2.length; int rem1 = encoded1[0][1], rem2 = encoded2[0][1];//初始化 while (i < len1 && j < len2) { int multi1 = encoded1[i][0]; int multi2 = encoded2[j][0]; int min = Math.min(rem1, rem2); toResult(multi1 * multi2, min);//乘积和 //-------肯定有一个是0---------// rem1 -= min; rem2 -= min; //为0的那个下移,不为0的那个保持原状,但是freq得去掉已经计算过的 if (rem1 == 0) { i++; if (i < len1) { rem1 = encoded1[i][1];//下移 } } if (rem2 == 0) { j++; if (j < len2) { rem2 = encoded2[j][1]; } } } return res; } private void toResult(int num, int freq) { if (res.isEmpty()) {//如果是空的 res.add(Arrays.asList(num, freq));//直接添加 } else {//如果不是空的 List<Integer> list = res.get(res.size() - 1);//取出最后一个值, if (list.get(0) == num) {//跟最后一个相等,那就继续往上加 list.set(1, list.get(1) + freq); } else { res.add(Arrays.asList(num, freq));//否则加载末尾 } } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。