1. 删除数位求是否能整除
思路:
- 遍历:假设a有n位,b有m位,如果用遍历的话,最多有种可能(Cn1 + …… + Cn(n-1))*(Cm1 + …… + Cm(m-1))种可能性
- 从“贪心”的角度来说,应该从删除位数少向删除位数多遍历
- 从题意来看,a、b至少得留一位,不能全删除了
/*
参数a、b是数组的形式,因为数组才好操作删除位数。不知道纯数字怎么删除某一位的
*/
console.log(getRes([1, 2, 3, 4], [9, 9])); // 2
console.log(getRes([1, 2, 3, 4], [9, 9,9,9,9])); // 1
function getRes(a, b) {
// 直接整除,不用操作
if(isBase(a, b)) {
return 0
} else {
let alen = a.length, blen = b.length, bmap = new Map(), result = Number.MAX_VALUE
for(let i = 0; i <= alen - 1; ++i) {
let res1 = removeNum(i, a);
for(let j = 0; j <= blen - 1; ++j) {
if(!bmap.has(j)) {
let res = removeNum(j, b);
bmap.set(j, res)
}
let res2 = bmap.get(j);
if(gotyou(res1, res2)) {
result = Math.min(result, i + j);
}
}
}
return result === Number.MAX_VALUE ? -1 : result;
}
}
function isBase(a, b) {
let num1 = parseInt(a.join(''))
let num2 = parseInt(b.join(""));
if (num1 === 0|| num2 === 0) return true;
return num1 % num2 === 0 || num2 % num1 === 0;
}
/*
j是要删除的位数;b是数组
返回删除j位数后数组的组合
*/
function removeNum(j, b) {
let res = [], currentList = [];
// 删除j位,等价于从b中取出b.length - j位。
// 也就是从b.length位中取b.length - j位的组合,但是不能破坏原有的顺序,如1234只能取出123来,却不能取出321来————这里可以参考力扣46题全排列,用回溯!
let targetCount = b.length - j, used = new Array(b.length).fill(false);
backTrack(currentList, b, used, 0);
return res
function backTrack(currentList, nums, used, start) {
if(currentList.length === targetCount) {
// console.log(currentList);
// 注意复杂数据类型的赋值,这里浅拷贝下!
res.push(currentList.slice(0));
return
}
for(let i = start; i < nums.length; ++i) {
if(used[i] === true) {
continue
} else if (nums.length - i + 1 < targetCount - currentList.length) {
// 这种情况下,往后取肯定不够targetCount位,就直接返回吧,不要往下了
return;
} else {
currentList.push(nums[i]);
used[targetCount] === true;
// 为了保证顺序,从i+1往后取
backTrack(currentList, nums, used, i + 1);
currentList.pop(nums[i]);
used[targetCount] === true;
}
}
}
}
// 删除了某一位后拿来这里比较下,看能不能整除
function gotyou(arr1, arr2) {
for(let num1 of arr1) {
for(let num2 of arr2) {
if (isBase(num1, num2)) {
return true;
}
}
}
return false
}
2. 长城数
思路:
- 分别找到奇、偶数项的最大值。如果最大值相同就短的加一,即如果一共是偶数个数,随便哪个加1,如果一共是奇数个数,那就偶数位加1——>所以都让偶数位加1就够了
- 今天京东笔试也考到了长城数,但是有点差别。
console.log(getNum([1,1,4,5,1,4])); // 11
function getNum(arr) {
let oddMax = 0, evenMax = 0, res = 0;
for(let i = 0; i < arr.length; ++i) {
if(i % 2 === 0) {
oddMax = Math.max(oddMax, arr[i]);
} else {
evenMax = Math.max(evenMax, arr[i]);
}
}
if(oddMax === evenMax) {
evenMax += 1;
}
for (let i = 0; i < arr.length; ++i) {
if (i % 2 === 0) {
res += (oddMax - arr[i]);
} else {
res += (evenMax - arr[i]);
}
}
return res;
}
3. 百年好“e”
思路:
- 题干里说了两个限制条件,在'好e'`最多`的情况下,需要修改的`最少`位数。而当字符串位数已知的时候,'好e'的个数是可以预先求出来的,如3位、4位字符,最多一个'好e';5位字符,最多两个好e。
- 我想的是求出来'好e'的个数,就知道其组合了,然后和原来的字符串比较即可。但是我这里想错了,如'reddee'最多有两个'好e',最终应该是'rederd'或者'deredr',但是'redred'也是两个'好e'呀,情况还有很多种,所以此路不通
- 暂无思路,也没看到好的解法。
4. 三元组数
- 思路:当时时间紧迫,我就用了暴力解法,过了60%。思路是,遍历数组,当arr[i] === arr[j]时,看i, j中间有几个符合要求的数。 function getNum(arr) {
let sum = 0
for(let i = 0; i < arr.length - 1; ++i) {
for(let j = i + 1; j < arr.length; ++j) {
if(arr[j] === arr[i]) {
sum += getPart(i, j);
}
}
}
return sum
function getPart(i, j) {
let res1 = 0
for(let z = i + 1; z < j; ++z) {
if(arr[z] < arr[i]) {
res1++;
}
}
return res1
}
}
console.log(getNum([3, 1, 3, 4, 3, 4])); // 3
- 优化思路,上面确实存在重复计算的情况,如[3,1,2,3,1,3],算arr[0] 和arr[5]之间的三元组数时,可以用 arr[0] 和 arr[3] 加上 arr[3] 和arr[5]之间的三元组数,而前者是算过的,那就用个备忘录memo去记录一下,也就是用空间换时间啦,可以降低时间复杂度。 function getNum(arr) {
let sum = 0, memo = [-1,-1,-1];
for (let i = 0; i < arr.length - 1; ++i) {
for (let j = i + 1; j < arr.length; ++j) {
if (arr[j] === arr[i]) {
sum += getPart(i, j);
}
}
}
return sum;
function getPart(i, j) {
console.log(i,j);
let res1 = 0;
if (memo[0] !== i) {
// 这种情况下就是备忘录没用
for (let z = i + 1; z < j; ++z) {
if (arr[z] < arr[i]) {
res1++;
}
}
} else {
// 备忘录起作用了
for (let z = memo[1] + 1; z < j; ++z) {
if (arr[z] < arr[i]) {
res1++;
}
}
res1 += memo[2]
}
// memo记录了起点和终点,以及这个中间符合要求的三元组数!
memo = [i, j, res1];
return res1;
}
}
console.log(getNum([3, 1 ,3 ,4 ,3, 4])); // 3
- 但是这个memo还不够,还是有重复计算的情况,再优化吧!