728. 自除数
2022.3.31 每日一题
题目描述
自除数 是指可以被它包含的每一位数整除的数。
- 例如,128 是一个 自除数 ,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。
自除数 不允许包含 0 。
给定两个整数 left 和 right ,返回一个列表,列表的元素是范围 [left, right] 内所有的 自除数 。
示例 1:
输入:left = 1, right = 22
输出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
示例 2:
输入:left = 47, right = 85
输出:[48,55,66,77]
提示:
1 <= left <= right <= 10^4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/self-dividing-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
java
class Solution {
public List<Integer> selfDividingNumbers(int left, int right) {
//有什么好的办法吗
List<Integer> list = new ArrayList<>();
for(int i = left; i <= right; i++){
int num = i;
boolean flag = true;
while(num != 0){
int t = num % 10;
if(t == 0 || i % t != 0){
flag = false;
break;
}
num /= 10;
}
if(flag)
list.add(i);
}
return list;
}
}
python
class Solution:
def selfDividingNumbers(self, left: int, right: int) -> List[int]:
res = []
for i in range(left, right + 1):
temp = i
flag = True
# 如果temp等于0
while temp > 0:
t = temp % 10
if t == 0 or i % t != 0:
flag = False
break
temp //= 10
if flag:
res.append(i)
return res
954. 二倍数对数组
2022.4.1 每日一题
题目描述
给定一个长度为偶数的整数数组 arr,只有对 arr 进行重组后可以满足 “对于每个 0 <= i < len(arr) / 2,都有 arr[2 * i + 1] = 2 * arr[2 * i]” 时,返回 true;否则,返回 false。
示例 1:
输入:arr = [3,1,3,6]
输出:false
示例 2:
输入:arr = [2,1,2,6]
输出:false
示例 3:
输入:arr = [4,-2,2,-4]
输出:true
解释:可以用 [-2,-4] 和 [2,4] 这两组组成 [-2,-4,2,4] 或是 [2,4,-2,-4]
提示:
0 <= arr.length <= 3 * 10^4
arr.length 是偶数
-10^5 <= arr[i] <= 10^5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/array-of-doubled-pairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
class Solution {
int mod = (int)1e6;
public boolean canReorderDoubled(int[] arr) {
//就是什么呢,就是有len/2组两倍关系的数对
//直接排序,然后从小到大找这种关系,如果都能找到,那么true
int l = arr.length;
Arrays.sort(arr);
Map<Integer, List<Integer>> map = new HashMap<>();
for(int i = 0; i < l; i++){
int t = arr[i];
List<Integer> list = map.getOrDefault(t, new ArrayList<>());
list.add(i);
map.put(t, list);
}
//0拿出来单独判断,如果有偶数个0跳过
List<Integer> zero = map.getOrDefault(0, new ArrayList<>());
if(zero.size() % 2 == 1)
return false;
for(int i = 0; i < l; i++){
int t = arr[i];
if(t == mod || t == 0)
continue;
int need = 0;
if(t >= 0){
need = t * 2;
}else{
if(t % 2 != 0)
return false;
need = t / 2;
}
if(!map.containsKey(need)){
return false;
}
List<Integer> list = map.get(need);
int idx = list.get(0);
list.remove(0);
arr[idx] = mod;
if(list.isEmpty())
map.remove(need);
else
map.put(need, list);
}
return true;
}
}
其实直接成组的判断就可以了
例如,有5个1,那么必须就有5个2这种
这里不需要特殊判断0
class Solution {
static int N = 100010, M = N * 2;
static int[] cnts = new int[M * 2];
public boolean canReorderDoubled(int[] arr) {
Arrays.fill(cnts, 0);
List<Integer> list = new ArrayList<>();
for (int i : arr) {
if (++cnts[i + M] == 1) list.add(i);
}
Collections.sort(list, (a,b)->Math.abs(a)-Math.abs(b));
for (int i : list) {
if (cnts[i * 2 + M] < cnts[i + M]) return false;
cnts[i * 2 + M] -= cnts[i + M];
}
return true;
}
}
420. 强密码检验器
2022.4.2 每日一题
题目描述
如果一个密码满足下述所有条件,则认为这个密码是强密码:
- 由至少 6 个,至多 20 个字符组成。
- 至少包含 一个小写 字母,一个大写 字母,和 一个数字 。
- 同一字符 不能 连续出现三次 (比如 “…aaa…” 是不允许的, 但是 “…aa…a…” 如果满足其他条件也可以算是强密码)。
给你一个字符串 password ,返回 将 password 修改到满足强密码条件需要的最少修改步数。如果 password 已经是强密码,则返回 0 。
在一步修改操作中,你可以:
- 插入一个字符到 password ,
- 从 password 中删除一个字符,或
- 用另一个字符来替换 password 中的某个字符。
示例 1:
输入:password = “a”
输出:5
示例 2:
输入:password = “aA1”
输出:3
示例 3:
输入:password = “1337C0d3”
输出:0
提示:
1 <= password.length <= 50
password 由字母、数字、点 ‘.’ 或者感叹号 ‘!’
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/strong-password-checker
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
做了半天,写了老长,根据长度分三种情况
如果小于6,那么添加优先
如果满足长度条件,替换就可以了
如果大于20,那么肯定需要删除len-20个字符,但是删除哪个字符是有讲究的,因为删除会影响替换次数
例如有六个连续的字符,那么删除1个就可以减少1次替换,也就是余数为0的情况
同理,余数为1,删除两个可以减少替换次数
所以需要统计连续字符的个数,然后先删除余数为0的,再删除余数为1的…
我这里用map记录的,可以看看题解的代码,有很简洁的,这,任重道远
class Solution {
public int strongPasswordChecker(String password) {
//假设当前密码中包含的字符种类有t个
//如果小于6个,那么肯定是添加操作优先,如果是好多个相同的字符,那么还需要替换
//需要的操作数就是max(6 - len, 3 - t)
//如果在20个以内,那么肯定是替换操作优先,就需要看是否有连续三个字符,如果出现了连续三个,直接替换
//需要的操作数就是连续字符的个数,如果没有连续的字符但是种类不足,那只需要随便替换两个就行了
//如果是20个以上,那么就是删除操作优先,需要删除的数目就是len - 20
//所以当出现了连续的字符时,需要优先考虑删除操作
//如果删除以后还是相同,那么再考虑替换操作
//"bbaaaaaaaaaaaaaaacccccc"这个例子出错了,如果先删除后替换,那么删除的是3个a,然后替换需要替换4个a两个c
//但是实际上,删除两个a一个c,那么替换的时候,替换1个c,4个a就可以了
//所以这给了个什么启发呢,为了让替换次数最少,需要看情况删除
//如果连续的字符除以3余数为0,那么可以删除1个,从而使替换次数少1
//如果余数为1,那么删除两个,使替换次数少1
//如果余数为2,那么删除三个,使替换次数少1
//当然,前提是删除次数还有的时候
//所以第一步需要先统计字符串中连续字符的个数,先删除余数为0的,然后1的,然后2的
//如果删除次数不够了,就开始替换
//如果删除完以后,依然有次数,那么就直接对连续的进行删除就行了,因为都是余数为2
int[] type = new int[3];
int l = password.length();
//System.out.println(l);
for(char c : password.toCharArray()){
if(Character.isDigit(c))
type[0] = 1;
else if(Character.isLowerCase(c))
type[1] = 1;
else if(Character.isUpperCase(c))
type[2] = 1;
}
int kind = 0;
for(int t : type)
kind += t;
if(l < 6){
return Math.max(6 - l, 3 - kind);
}else if(l <= 20){
int continuous = 0;
char temp = ' ';
int modify = 0;
for(char c : password.toCharArray()){
if(temp != c){
//如果有连续三个的就替换一个
modify += continuous / 3;
temp = c;
continuous = 1;
}else{
continuous++;
}
}
modify += continuous / 3;
return Math.max(modify, 3 - kind);
}else{
//当大于20个时,肯定是优先删除,如果删除到只剩下20了,再和上面一样进行替换
//需要删除的数目
int del = l - 20;
char temp = ' ';
Map<Integer, List<Integer>> map = new HashMap<>();
int continuous = 0;
for(char c : password.toCharArray()){
if(temp != c){
int remain = continuous % 3;
if(continuous >= 3){
List<Integer> list = map.getOrDefault(remain, new ArrayList<>());
list.add(continuous);
map.put(remain, list);
}
temp = c;
continuous = 1;
}else{
continuous++;
}
}
int remain = continuous % 3;
if(continuous >= 3){
List<Integer> list = map.getOrDefault(remain, new ArrayList<>());
list.add(continuous);
map.put(remain, list);
}
//为了能使替换次数减少,先删除余数为0的
List<Integer> zero = map.getOrDefault(0, new ArrayList<>());
List<Integer> two = map.getOrDefault(2, new ArrayList<>());
while(del > 0 && !zero.isEmpty()){
int t = zero.remove(0);
t--;
del--;
if(t >= 3)
two.add(t);
}
List<Integer> one = map.getOrDefault(1, new ArrayList<>());
while(del > 1 && !one.isEmpty()){
int t = one.remove(0);
t -= 2;
del -= 2;
if(t >= 3)
two.add(t);
}
//System.out.println(zero.size());
//System.out.println(one.size());
//到这里,剩下的连续的都是余数为2或者说删除次数还多
//如果删除次数还多,那么直接在任意连续的地方进行删除,因为不过改变替换次数
//另外,如果删除次数还多,那么只有two这个list有数
//那么就需要进行替换了
int replace = 0;
for(int t : zero){
replace += t / 3;
}
for(int t : one){
replace += t / 3;
}
for(int t : two){
if(del > 0){
int jian = Math.min(del, t - 2);
t -= jian;
del -= jian;
}
replace += t / 3;
}
return l - 20 + Math.max(replace, 3 - kind);
}
}
}