编程题
650.只有两个键的键盘
最初在一个记事本上只有一个字符 ‘A’。你每次可以对这个记事本进行两种操作:
Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的)。
Paste (粘贴) : 你可以粘贴你上一次复制的字符。
给定一个数字 n 。你需要使用最少的操作次数,在记事本中打印出恰好 n 个 ‘A’。输出能够打印出 n 个 ‘A’ 的最少操作次数。
示例 1:
输入: 3
输出: 3
解释:
最初, 我们只有一个字符 ‘A’。
第 1 步, 我们使用 Copy All 操作。
第 2 步, 我们使用 Paste 操作来获得 ‘AA’。
第 3 步, 我们使用 Paste 操作来获得 ‘AAA’。
说明:
n 的取值范围是 [1, 1000] 。
思路:
分情况:
第一种当n为质数时,只能复制单个并粘贴n次;
第二种当n为合数时,先找到n的最大因子i,得到最少操作次数的情况发生在已经有(n / i)个’A’,其中i为最小的能整除n的数(i大于1),然后复制1次,粘贴n / i - 1次,,说明只要操作i次就能得到n个’A’。
652.寻找重复的子树
给定一棵二叉树,返回所有重复的子树。对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。
两棵树重复是指它们具有相同的结构以及相同的结点值。
示例 1:
1
/ \
2 3
/ / \
4 2 4
/
4
下面是两个重复的子树:
2
/
4
和
4
因此,你需要以列表的形式返回上述重复子树的根结点。
思路:
假设每棵子树都有一个唯一标识符:把每个节点开始的子树id保存,然后判断是否存在重复的子树。
一个节点的左孩子 id 为 x,右孩子 id 为 y,那么该节点的 id 为 ( value, x, y),只有当两个子树的 id 相同时,认为这两个子树是相同的。
.
653. 两数之和 IV - 输入 BST
给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
案例 1:
输入:
5
/ \
3 6
/ \ \
2 4 7
Target = 9
输出: True
案例 2:
输入:
5
/ \
3 6
/ \ \
2 4 7
Target = 28
输出: False
思路:
首先遍历树,将树的元素存入一个队列1,再创建一个空队列2
然后从队列1首部删除一个元素 y
检查 队列1和队列2中是否存在 x=Target - y如果存在,返回 True。
否则,将 y加入 队列2。
重复步骤一至三,直到 队列1 为空。
如果 队列1为空,返回 False
.
1480. 一维数组的动态和,给你一个数组 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] 。
示例 2:
输入:nums = [1,1,1,1,1]
输出:[1,2,3,4,5]
解释:动态和计算过程为 [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1] 。
示例 3:
输入:nums = [3,1,2,10,1]
输出:[3,4,6,16,17]
提示:
1 <= nums.length <= 1000
-10^6 <= nums[i] <= 10^6
解:
思路:数组索引i位置,就是和数组索引i-1位置的数相加,因为数组索引i-1已经是和前面的数相加过的和,所以直接和他相加就行
class Solution {
public int[] runningSum(int[] nums) {
//从数组索引1开始,因为数组索引0的数不用变
for(int i = 1; i < nums.length; i++){
//比如数组索引i位置,就是和数组索引i-1位置的数相加,因为数组索引i-1已经是和前面的数相加过的和,所以直接和他相加就行
nums[i] += nums[i - 1];
}
return nums;
}
}
剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
示例 2:
输入: s = “lrloseumgh”, k = 6
输出: “umghlrlose”
限制:
1 <= k < s.length <= 10000
解:
直接将要左旋的n位字符串截取后用+ 连接起来
class Solution {
public String reverseLeftWords(String s, int n) {
// 截取再 + 连接
String str = s.substring(n, s.length()) + s.substring(0, n);
return str;
}
}
- 宝石与石头
给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头。 S 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。
J 中的字母不重复,J 和 S中的所有字符都是字母。字母区分大小写,因此"a"和"A"是不同类型的石头。
示例 1:
输入: J = “aA”, S = “aAAbbbb”
输出: 3
示例 2:
输入: J = “z”, S = “ZZ”
输出: 0
注意:
S 和 J 最多含有50个字母。
J 中的字符不重复。
解:
遍历字符串 s,对于 s 中的每个字符,遍历一次字符串 J,再J中去挨个比较
如果其和 J 中的某一个字符相同,则是宝石,并计数
class Solution {
public int numJewelsInStones(String J, String S) {
int Count = 0;
//获取长度
int JLength = J.length(), SLength = S.length();
//从s中每一种宝石去找
for (int i = 0; i < SLength; i++) {
char stone = S.charAt(i);
//每一种s类型要在j中寻找
for (int j = 0; j < JLength; j++) {
char jewel = J.charAt(j);
if (stone == jewel) {
//找到后让count + 1,并跳出此次循环
Count++;
break;
}
}
}
return Count;
}
}
- 统计一致字符串的数目
给你一个由不同字符组成的字符串 allowed 和一个字符串数组 words 。如果一个字符串的每一个字符都在 allowed 中,就称这个字符串是 一致字符串 。
请你返回 words 数组中 一致字符串 的数目。
示例 1:
输入:allowed = “ab”, words = [“ad”,“bd”,“aaab”,“baa”,“badab”]
输出:2
解释:字符串 “aaab” 和 “baa” 都是一致字符串,因为它们只包含字符 ‘a’ 和 ‘b’ 。
示例 2:
输入:allowed = “abc”, words = [“a”,“b”,“c”,“ab”,“ac”,“bc”,“abc”]
输出:7
解释:所有字符串都是一致的。
示例 3:
输入:allowed = “cad”, words = [“cc”,“acd”,“b”,“ba”,“bac”,“bad”,“ac”,“d”]
输出:4
解释:字符串 “cc”,“acd”,“ac” 和 “d” 是一致字符串。
提示:
1 <= words.length <= 104
1 <= allowed.length <= 26
1 <= words[i].length <= 10
allowed 中的字符 互不相同 。
words[i] 和 allowed 只包含小写英文字母。
解:
循环取出字符串数组words中的字符串
然后用字符串words[ i ]中的字符挨个与allowed中的字符比较
如果字符串words[ i ]的每一个字符都在 allowed 中
就将计数加一.
否则就退出循环
再取出下一个字符串比较
直到words中的字符串比较完,后输出计数
- 有多少小于当前数字的数字
给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目。
换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 nums[j] < nums[i] 。
以数组形式返回答案。
示例 1:
输入:nums = [8,1,2,2,3]
输出:[4,0,1,1,3]
解释:
对于 nums[0]=8 存在四个比它小的数字:(1,2,2 和 3)。
对于 nums[1]=1 不存在比它小的数字。
对于 nums[2]=2 存在一个比它小的数字:(1)。
对于 nums[3]=2 存在一个比它小的数字:(1)。
对于 nums[4]=3 存在三个比它小的数字:(1,2 和 2)。
示例 2:
输入:nums = [6,5,4,8]
输出:[2,1,0,3]
示例 3:
输入:nums = [7,7,7,7]
输出:[0,0,0,0]
提示:
2 <= nums.length <= 500
0 <= nums[i] <= 100
解:对于数组中的每一个元素,我们都遍历数组一次,统计小于当前元素的数的数目。
class Solution {
public int[] smallerNumbersThanCurrent(int[] nums) {
int n = nums.length;
int[] newnums = new int[n];
for (int i = 0; i < n; i++) {
int cnt = 0;
for (int j = 0; j < n; j++) {
if (nums[j] < nums[i]) {
cnt++;
}
}
newnums [i] = cnt;
}
return newnums ;
}
}
LCP 06. 拿硬币
桌上有 n 堆力扣币,每堆的数量保存在数组 coins 中。我们每次可以选择任意一堆,拿走其中的一枚或者两枚,求拿完所有力扣币的最少次数。
示例 1:
输入:[4,2,1]
输出:4
解释:第一堆力扣币最少需要拿 2 次,第二堆最少需要拿 1 次,第三堆最少需要拿 1 次,总共 4 次即可拿完。
示例 2:
输入:[2,3,10]
输出:8
限制:
1 <= n <= 4
1 <= coins[i] <= 10
解:
循环数组,计算数组元素与2的余数,如果余数为 0 则可以按照 2 的倍数将金币拿完,如果余数为 1 拿完硬币的次数则是 元素 除 2 再加拿最后一枚硬币的次数
class Solution {
public int minCount(int[] coins) {
int a = 0;
for(int i = 0;i < coins.length;i++){
if(coins[i] % 2 == 0){
a = a + coins[i] / 2;
}else {
a = a + coins[i] / 2 + 1;
}
}
return a;
}
}
- 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
解:遍历数组,将每一个数拿出来比较,计数相等的次数如果只有1次 就返回它
class Solution {
public int singleNumber(int[] nums) {
int single = 0;
for(int i = 0;i < nums.length;i++){
for(int j = 0;j < nums.length;j++){
int count = 0;
if(nums[i] == nums[j]){
count = count ++;
}
if(count == 2){
break;
}else {
single = nums[j];
}
}
}
return single;
}
}
- 山脉数组的峰顶索引
符合下列属性的数组 arr 称为 山脉数组 :
arr.length >= 3
存在 i(0 < i < arr.length - 1)使得:
arr[0] < arr[1] < … arr[i-1] < arr[i]
arr[i] > arr[i+1] > … > arr[arr.length - 1]
给你由整数组成的山脉数组 arr ,返回任何满足 arr[0] < arr[1] < … arr[i - 1] < arr[i] > arr[i + 1] > … > arr[arr.length - 1] 的下标 i 。
示例 1:
输入:arr = [0,1,0]
输出:1
示例 2:
输入:arr = [0,2,1,0]
输出:1
示例 3:
输入:arr = [0,10,5,2]
输出:1
示例 4:
输入:arr = [3,4,5,1]
输出:2
示例 5:
输入:arr = [24,69,100,99,79,78,67,36,26,19]
输出:2
提示:
3 <= arr.length <= 104
0 <= arr[i] <= 106
题目数据保证 arr 是一个山脉数组
解:从左往右遍历直到山的高度不再增长为止,
停止增长点就是峰顶,返回其下标
class Solution {
public int peakIndexInMountainArray(int[] arr) {
int i = 0;
while (arr[i] < arr[i+1]) {
i++;
}
return i;
}
}
面试题 05.07. 配对交换
配对交换。编写程序,交换某个整数的奇数位和偶数位,尽量使用较少的指令(也就是说,位0与位1交换,位2与位3交换,以此类推)。
示例1:
输入:num = 2(或者0b10)
输出 1 (或者 0b01)
示例2:
输入:num = 3
输出:3
提示:
num的范围在[0, 2^30 - 1]之间,不会发生整数溢出。
解:
分别取出数字二进制奇数位和偶数位
将奇数位的和下一个偶数位交换
- 玩筹码
数轴上放置了一些筹码,每个筹码的位置存在数组 chips 当中。
你可以对 任何筹码 执行下面两种操作之一(不限操作次数,0 次也可以):
将第 i 个筹码向左或者右移动 2 个单位,代价为 0。
将第 i 个筹码向左或者右移动 1 个单位,代价为 1。
最开始的时候,同一位置上也可能放着两个或者更多的筹码。
返回将所有筹码移动到同一位置(任意位置)上所需要的最小代价。
示例 1:
输入:chips = [1,2,3]
输出:1
解释:第二个筹码移动到位置三的代价是 1,第一个筹码移动到位置三的代价是 0,总代价为 1。
示例 2:
输入:chips = [2,2,2,3,3]
输出:2
解释:第四和第五个筹码移动到位置二的代价都是 1,所以最小总代价为 2。
提示:
1 <= chips.length <= 100
1 <= chips[i] <= 10^9
解:因为移动2个位置不需要代价,那么奇数位置移到奇数位置不用代价,偶数位置移到偶数位置不用代价,
然后分别统计奇数位置和偶数位置的个数,相当于把所有奇数放一起,所有偶数的放一起,
然后比较奇数的少还是偶数的少,
将少的那个个数移到多的个数位置上去
class Solution {
public int minCostToMoveChips(int[] position) {
int odd = 0;
int even = 0;
for (int i = 0; i < position.length; i++) {
if (position[i] % 2 == 0) {
even++;
} else{
odd++;
}
}
return Math.min(even, odd);
}
}