文章目录
1. 20200602——求1+2+…+n
面试题64. 求1+2+…+n
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
- 解法1:用&&或||的短路特性实现递归
- 将判断是否为递归的出口看作 A && B 表达式中的 A 部分,递归的主体函数看作 B 部分。如果不是递归出口,则返回 \textit{True}True,并继续执行表达式 B 的部分,否则递归结束。当然,你也可以用逻辑运算符 || 给出类似的实现,这里我们只提供结合逻辑运算符 && 的递归实现。
- 解法2:俄罗斯农民乘法,根据数的范围手动循环
- 考虑 A 和 B 两数相乘的时候我们如何利用加法和位运算来模拟,其实就是将 B 二进制展开,如果 B 的二进制表示下第 ii 位为 1,那么这一位对最后结果的贡献就是 A*(1<<i)A∗(1<<i) ,即 A<<iA<<i。我们遍历 B 二进制展开下的每一位,将所有贡献累加起来就是最后的答案,这个方法也被称作「俄罗斯农民乘法」
- [1,10000],所以 nn 二进制展开最多不会超过 1414 位,我们手动展开 1414 层代替循环即可
2. 20200605——除自身以外数组的乘积
238. 除自身以外数组的乘积
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
class Solution {
// public int[] productExceptSelf(int[] nums) {
// int n = nums.length;
// int[] left = new int[nums.length];
// int[] right = new int[nums.length];
// left[0] = 1;
// for(int i = 1;i<n;i++){
// left[i] = left[i-1]*nums[i-1];
// }
// // System.out.println(Arrays.toString(left));
// right[n-1] = 1;
// for(int i = n-2;i>=0;i--){
// right[i] = right[i+1]*nums[i+1];
// }
// // System.out.println(Arrays.toString(right));
// int[] res = new int[n];
// for(int i = 0;i<n;i++){
// res[i] = left[i]*right[i];
// }
// return res;
// }
// left O(n)变为 O(1)
// public int[] productExceptSelf(int[] nums) {
// int n = nums.length;
// // int[] left = new int[nums.length];
// int[] right = new int[nums.length];
// // System.out.println(Arrays.toString(left));
// right[n-1] = 1;
// for(int i = n-2;i>=0;i--){
// right[i] = right[i+1]*nums[i+1];
// }
// int left = 1;
// // System.out.println(Arrays.toString(right));
// int[] res = new int[n];
// for(int i = 0;i<n;i++){
// res[i] = left*right[i];
// left *= nums[i];
// }
// return res;
// }
// right 提前放到res里面去
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
// int[] left = new int[nums.length];
// int[] right = new int[nums.length];
int[] res = new int[n];
// System.out.println(Arrays.toString(left));
res[n-1] = 1;
for(int i = n-2;i>=0;i--){
res[i] = res[i+1]*nums[i+1];
}
int left = 1;
// System.out.println(Arrays.toString(right));
for(int i = 0;i<n;i++){
res[i] = left*res[i];
left *= nums[i];
}
return res;
}
}
3. 接雨水
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [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 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
- 解法一:单调栈
- 解法二:双指针
4. 20200609——灯泡开关
初始时有 n 个灯泡关闭。 第 1 轮,你打开所有的灯泡。 第 2 轮,每两个灯泡你关闭一次。 第 3
轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭)。第 i 轮,每 i 个灯泡切换一次开关。 对于第 n
轮,你只切换最后一个灯泡的开关。 找出 n 轮后有多少个亮着的灯泡。示例:
输入: 3
输出: 1
解释: 初始时, 灯泡状态 [关闭, 关闭, 关闭]. 第一轮后, 灯泡状态 [开启, 开启, 开启].
第二轮后, 灯泡状态 [开启, 关闭, 开启]. 第三轮后, 灯泡状态 [开启, 关闭, 关闭].你应该返回 1,因为只有一个灯泡还亮着。
Related Topics 脑筋急转弯 数学
思路:完全平方数的灯泡会亮着。
举例:
- 第3个灯泡:3=1*3,第1次被打开,第3次被关上。同理所有质数。
- 第4个灯泡:4=14=22,第1次被打开,第2次被关上,第4次被打开。(完全平方数)
- 第24个灯泡:24=124=212=38=46,所以是关闭的。
return (int)Math.pow(n,1/2d);
5. 20200613——三数之和
15. 三数之和
前置题:两数之和
思路:结合两数之和的思路,即排序后,从头选定一个数,再从尾部选定一个数,双指针。对于三数则是,选定第一个数a[i],第二个数则从i+1作为头部,再头尾双指针。
法一:
public List<List<Integer>> threeSum2(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if (i>0&&nums[i]==nums[i-1]) continue;
int k = nums.length-1;
for(int j=i+1;j<nums.length;j++){
if (j>i+1&&nums[j]==nums[j-1]) continue;
while (k>j && nums[k]+nums[i]+nums[j]>0){
k--;
}
if (k==j){
break;
}
if (nums[k]+nums[i]+nums[j]==0){
List<Integer> li = new ArrayList<>();
li.add(nums[i]);
li.add(nums[j]);
li.add(nums[k]);
list.add(li);
}
}
}
return list;
}
法二:结合hashmap
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
HashMap<Integer,Integer> map = new HashMap<>();
HashSet<Integer> used = new HashSet<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if (i>0&&nums[i]==nums[i-1]) continue;
for(int j=i+1;j<nums.length;j++){
// if (j>0&&nums[j]==nums[j-1]) continue;
if(map.containsKey(-nums[j]) && !used.contains(-nums[j])){
List<Integer> li = new ArrayList<>();
li.add(nums[i]);
li.add(nums[j]);
li.add(nums[map.get(-nums[j])]);
list.add(li);
used.add(-nums[j]);
}else{
map.put(nums[i]+nums[j],j);
}
}
map.clear();
used.clear();
}
return list;
}
力扣运行结果:
- 法一:24ms,44.3MB
- 法二:212ms,44.2MB
6. 20201023——回文链表
用双指针,边移动边逆转链表能达到 时间O(n) 空间O(1)的要求。
官方题解 的解法二虽然复杂度不及上面,但对递归的使用很巧妙。
class Solution {
private ListNode frontPointer;
private boolean recursivelyCheck(ListNode currentNode) {
if (currentNode != null) {
if (!recursivelyCheck(currentNode.next)) {
return false;
}
if (currentNode.val != frontPointer.val) {
return false;
}
frontPointer = frontPointer.next;
}
return true;
}
public boolean isPalindrome(ListNode head) {
frontPointer = head;
return recursivelyCheck(head);
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/hui-wen-lian-biao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。