文章目录
自守数、质数(素数)、约数、完全数
HJ99 自守数√
就是依次比较平方的尾数是否相等
let line;
while ((line = readline())) {
let count = 0;
for (let i = 0; i <= parseInt(line); i++) {
if (String(Math.pow(i, 2)).endsWith(String(i))) count++;
}
console.log(count);
}
HJ6 质数因子√√
从2开始到Math.sqrt,能整除就一直除下去
function g(num) {
let res = [];
for (let i = 2; i <= Math.sqrt(num); i++) {
while (num % i === 0) {
res.push(i);
num /= i;
}
}
if (num > 1) res.push(num);
console.log(res.join(" "));
}
let num = parseInt(readline());
g(num);
HJ56 完全数计算√√
只要能被整除就是它的约数。
第一个完全数是6,循环从6开始。
统计约数从1开始。
function g(num) {
let count = 0;
for (let i = 6; i <= num; i++) {
let sum = 0;
//统计因数的和,计数到该数的1/2即可
for (let j = 1; j <= i / 2; j++) {
if (i % j == 0) sum += j;
}
if (sum == i) count++;
}
console.log(count);
}
let num;
while ((num = parseInt(readline()))) {
g(num);
}
HJ60 查找组成一个偶数最接近的两个素数√
一分为二,每次两数加减1,判断两数是否为素数
素数判断,对于任意整数n,从2开始到Math.sqrt,能被整除则不是素数。
function isSuShu(n) {
if (n < 2) return false;
let res = true;
for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) res = false;
}
return res;
}
function getRes(n) {
let a = n / 2;
let b = a;
while (a > 1 && b > 1) {
if (isSuShu(a) && isSuShu(b)) {
break;
} else {
a--;
b++;
}
}
return [a,b];
}
let line;
while ((line = readline())) {
let [a, b] = getRes(Number(line));
console.info(a);
console.info(b);
}
数列
HJ100 等差数列√
前n项和公式为:Sn=n*a1+n(n-1)d/2 或 Sn=n(a1+an)/2
let n = parseInt(readline());
let count = 2;
let last = 2;
for (let i = 1; i < n; i++) {
last += 3;
count += last;
}
console.info(count);
let n = parseInt(readline());
console.info(2 * n + (n * (n - 1) * 3) / 2);
let n = parseInt(readline());
let count = 2;
for (let i = 1; i < n; i++) {
count += 2 + i * 3;
}
console.info(count);
HJ76 尼科彻斯定理√√
前n项和公式为:Sn=n*a1+n(n-1)d/2 或 Sn=n(a1+an)/2
从1开始到pow,依次循环找出首项a1
let n = Number(readline());
let res = [];
let pow = Math.pow(n, 3);
for (let a1 = 1; a1 < pow; a1 += 2) {
if (n * a1 + n * (n - 1) === pow) {
res.push(a1);
for (let j = 1; j < n; j++) {
res.push(a1 + j * 2);
}
}
}
console.info(res.join("+"));
HJ35 蛇形矩阵
let row = Number(readline());
let arr = [1];
for (var i = 2; i < row + 1; i++) {
arr.push(arr[arr.length - 1] + i);
}
for (var j = 0; j < row; j++) {
let str = "";
arr.slice(j).forEach((item) => {
str = str + (item - j) + " ";
});
console.log(str);
}
递归
HJ37 统计每个月兔子的总数√√
斐波那契数列:1 1 2 3 5 8 13 21 34 f(n)=f(n-1)+f(n-2) n>2,n从0开始
递归,从大到小,带缓存
let n = Number(readline());
let cash = {};
function dp(n) {
if (cash[n]) return cash[n];
if (n < 3) return 1;
cash[n - 1] = dp(n - 1);
cash[n - 2] = dp(n - 2);
return cash[n - 1] + cash[n - 2];
}
console.info(dp(n));
let readline = require("readline");
let rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
function getSum(month) {
if (month < 3) {
return 1;
} else {
return getSum(month - 1) + getSum(month - 2);
}
}
rl.on("line", function (line) {
console.info(getSum(line));
});
HJ22 汽水瓶√√
function drink(n, result) {
if (n < 2) {
return result;
} else if (n === 2) {
return result + 1;
}
result += parseInt(n / 3);
let m = parseInt(n / 3) + (n % 3);
return drink(m, result);
}
let line;
while (line = readline()) {
let res = drink(Number(line), 0);
console.info(res);
}
递归,从大到小
小于2个瓶盖返回0瓶汽水,等于2个瓶盖返回1瓶汽水。
每次递归返回当前瓶盖能换回的汽水+下一次递归
function g(n) {
if (n < 2) return 0;
if (n === 2) return 1;
return parseInt(n / 3) + g(parseInt(n / 3) + (n % 3));
}
let line;
while ((line = readline())) {
let n = g(Number(line));
if (n) console.info(n);
}
HJ61 放苹果√√
递归,从大到小
// 递归
// 设f(m,n) 为m个苹果,n个盘子的放法数目,则先对n作讨论,
// 当n>m(盘子大于苹果):必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即if(n>m) f(m,n) = f(m,m)
// 当n<=m(盘子小于等于苹果):不同的放法可以分成两类:
// 1、有至少一个盘子空着,即相当于f(m,n) = f(m,n-1);
// 2、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n) = f(m-n,n).
// 而总的放苹果的放法数目等于两者的和,即 f(m,n) =f(m,n-1)+f(m-n,n)
// 递归出口条件说明:
// 当n=1时,所有苹果都必须放在一个盘子里,所以返回1;
// 当没有苹果可放时,定义为1种放法;
// 递归的两条路,第一条n会逐渐减少,终会到达出口n==1;
// 第二条m会逐渐减少,因为n>m时,我们会return f(m,m) 所以终会到达出口m==0.
function count(apple, disk) {
if (apple === 0 || disk === 1) {
return 1;
} else if (disk > apple) {
return count(apple, apple);
} else {
return count(apple, disk - 1) + count(apple - disk, disk);
}
}
let [apple, disk] = readline().split(" ").map(Number);
console.info(count(apple, disk));
HJ91 走方格的方案数√
递归,从上往下
// f(m, n) = f(m, n - 1) + f(m - 1, n)
const dp = (m, n) => {
if (m === 0 || n === 0) return 1;
// 目的地的上一步只可能是同一行的左侧或者同一列的上侧
return dp(m, n - 1) + dp(m - 1, n);
};
while ((line = readline())) {
const [n, m] = line.split(" ").map(Number);
console.log(dp(m, n));
}
余数
HJ53 杨辉三角的变形
余数
//杨辉三角规律 行号 第一个偶数
// 1 1 -1
// 1 1 1 2 -1
// 1 2 3 2 1 3 2
// 1 3 6 7 6 3 1 4 3
// 1 4 10 16 19 16 10 4 1 5 2
// 1 5 15 30 45 51 45 30 15 5 1 6 4
//
// 首个偶数在该行第几个的规律: -1 -1 (2 3 2 4)···(2 3 2 4)
let res = [2, 3, 2, 4];
let line;
while ((line = readline())) {
let n = Number(line);
if (n <= 2) {
console.info(-1);
} else {
console.info(res[(n + 1) % 4]);
}
}
HJ55 挑7√(中级)
function getSevenCount() {
if (Number(line) < 7) return 0;
let res = 0;
for (let i = 7; i <= Number(line); i++) {
if (i % 7 === 0 || i.toString().split("").includes("7")) {
res++;
}
}
return res;
}
let line;
while ((line = readline())) {
console.info(getSevenCount(line));
}
HJ57 高精度整数加法√(中级)
// 我们将两个字符串从尾到头进行处理
// 逐位相加,保留个位数字到结果字符串中,并记录进位的值在下一次循环中再次逐位相加
// 最终输出结果字符串
function sumBig(str1, str2) {
const a = str1.split("");
const b = str2.split("");
let c = 0;
let res = "";
while (a.length || b.length || c) {
c += ~~a.pop() + ~~b.pop(); // 个位求和
res = (c % 10) + res; // 记录
c = c > 9 ? 1 : 0; // 是否有进位
}
return res;
}
console.log(sumBig(readline(), readline()));
最大公约数、最小公倍数
HJ108 求最小公倍数√√
先求最大公约数,再求最小公倍数
最小公倍数 = (x*y)/最大公约数
function gongyue(a, b) {
while (a % b !== 0) {
let temp = a % b;
a = b;
b = temp;
}
return b;
}
function gongbei(a, b) {
return (a * b) / gongyue(a, b);
}
let [a, b] = readline().split(" ").map(Number);
console.info(gongbei(a, b));
最长回文子串
HJ85 最长回文子串√
找到回文中心点(BAB和BAAB两种),从里向外依次扩张
function g(l, r, str) {
while (l >= 0 && r < str.length && str[l] === str[r]) {
l--;
r++;
}
return r - l - 1;
}
function getMaxHuiLength(str) {
let max = 0;
for (let i = 0; i < str.length; i++) {
let res = g(i, i + 1, str);
max = Math.max(res, max);
res = g(i, i + 2, str);
max = Math.max(res, max);
}
return max;
}
let s = readline();
console.info(getMaxHuiLength(s));
暴力解,获取全部字串并依次判断是否为回文,同时不断更新最长的字串长度
function isHui(str) {
for (let i = 0; i < str.length; i++) {
if (str[i] != str[str.length - 1 - i]) {
return false;
}
}
return true;
}
function getMaxHuiLength(str) {
let currentHuiLength = 0;
let maxHuiLength = 0;
for (let i = 0; i < s.length; i++) {
for (let j = i; j < s.length; j++) {
let str = s.substring(i, j + 1);
if (isHui(str)) {
currentHuiLength = str.length;
}
maxHuiLength = Math.max(currentHuiLength, maxHuiLength);
}
}
return maxHuiLength;
}
let s = readline();
console.info(getMaxHuiLength(s));
HJ32 密码截取√√(中级)
// 密码截取
function getStringLength(key) {
let maxLength = 0;
let len = key.length;
for (let i = 0; i < len; i++) {
// 第一种情况 ABBA
var low = i; // 左指针
var high = i + 1; // 右指针
// 相等但无越界
while (low >= 0 && high < len && key[low] == key[high]) {
low--;
high++;
}
maxLength = Math.max(maxLength, high - low - 1);
// 第二种情况 ABBBA
low = i; // 左指针
high = i + 2; // 右指针
while (low >= 0 && high < len && key[low] == key[high]) {
low--;
high++;
}
maxLength = Math.max(maxLength, high - low - 1);
}
console.log(maxLength);
}
var line = readline();
getStringLength(line);
公共子串
HJ75 公共子串计算√(中级)
let str1 = readline();
let str2 = readline();
if (str1.length > str2.length) {
[str1, str2] = [str2, str1];
}
let max = 0;
for (let i = 0; i < str1.length; i++) {
for (let j = i + 1; j <= str1.length; j++) {
let s = str1.slice(i, j);
if (str2.indexOf(s) > -1) {
max = Math.max(max, s.length);
}
}
}
console.info(max);
HJ65 查找两个字符串a,b中的最长公共子串√(中级)
// 总体思路:从短的字符串中取子串,看其在长字符串中是否存在
let s1 = readline();
let s2 = readline();
if (s1.length > s2.length) {
[s1, s2] = [s2, s1];
}
let length = 0;
let res = "";
for (let i = 0; i < s1.length; i++) {
for (let j = i + 1; j <= s1.length; j++) {
let sub = s1.slice(i, j);
if (s2.includes(sub)) {
if (j - i > length) {
res = sub;
length = j - i;
}
} else {
break;
}
}
}
console.info(res);
最长递增子序列(动态规划系列)一维dp数组
dp[i]表示以nums[i]这个数结尾的“最长递增子序列的长度”。
function lis(nums) {
// base case: dp数组全都初始化为1
let dp = Array(nums.length).fill(1);
for (let i = 0; i < nums.length; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
let res = Math.max(0, ...dp);
return res;
}
HJ103 Redraiment的走法√√(中级)
function lis(nums) {
// base case: dp数组全都初始化为1
let dp = Array(nums.length).fill(1);
for (let i = 0; i < nums.length; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
let res = Math.max(0, ...dp);
return res;
}
let line;
while ((line = readline())) {
console.log(lis(readline().split(' ').map(Number)));
}
HJ24 合唱队√√(中级)
最长
let num;
while ((num = readline())) {
//186 186 150 200 160 130 197 200
const arr = readline().split(" ").map(Number);
//1,1,1,2,2,1,3,4
let dp1 = lis(arr);
//3,3,2,3,2,1,1,1
let dp2 = lis(arr.reverse()).reverse();
let max = 0;
for (let i = 0; i < dp1.length; i++) {
max = Math.max(max, dp1[i] + dp2[i] - 1);
}
console.log(arr.length - max);
}
function lis(nums) {
// base case: dp数组全都初始化为1
let dp = Array(nums.length).fill(1);
for (let i = 0; i < nums.length; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
return dp;
}
最大子数组(动态规划系列)
dp[i]表示以nums[i]这个数结尾的“最大子数组和”。
let num;
while ((num = readline())) {
let res = maxSubArray(num.split(" ").map(Number));
console.info(res);
}
function maxSubArray(nums) {
let n = nums.length;
if (n === 0) return 0;
// base case
// 第一个元素面前没有子数组
let dp = Array(n);
dp[0] = nums[0];
// 状态转移方程
for (let i = 1; i < n; i++) {
dp[i] = Math.max(nums[i], nums[i] + dp[i - 1]);
}
let res = Math.max(...dp);
return res;
}
最长公共子序列(动态规划系列)二维dp数组
function longestCommonSubsequence1(str1, str2) {
let dp = function (i, j) {
if (i === -1 || j === -1) return 0;
if (str1[i] === str2[j]) {
return dp(i - 1, j - 1) + 1;
} else {
return Math.max(dp(i - 1, j), dp(i, j - 1));
}
};
return dp(str1.length - 1, str2.length - 1);
}
function longestCommonSubsequence2(str1, str2) {
let m = str1.length;
let n = str2.length;
let dp = Array(m + 1)
.fill()
.map((item) => Array(n + 1).fill(0));
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (str1[i - 1] === str2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
}
}
}
return dp[m][n];
}
let res1 = longestCommonSubsequence1("abcde", "aceb");
console.info(res1);
let res2 = longestCommonSubsequence2("abcde", "aceb");
console.info(res2);
动态规划
HJ52 计算字符串的编辑距离(中级)二维dp数组
dp table
function minDistance(word1, word2) {
let len1 = word1.length;
let len2 = word2.length;
let dp = Array(len1 + 1)
.fill()
.map((item) => Array(len2 + 1).fill(0)); //dp数组
for (let i = 1; i <= len1; i++) dp[i][0] = i;
for (let j = 1; j <= len2; j++) dp[0][j] = j;
for (let i = 1; i <= len1; i++) {
for (let j = 1; j <= len2; j++) {
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(
dp[i - 1][j] + 1, //插入
dp[i][j - 1] + 1, //删除
dp[i - 1][j - 1] + 1 //替换
);
}
}
}
return dp[len1][len2];
}
let line;
while ((line = readline())) {
console.info(minDistance(line, readline()));
}
最长回文子序列(动态规划系列)二维dp数组
function longestPalindromeSubsequence(str) {
let n = str.length;
let dp = Array(n)
.fill()
.map((item) => Array(n).fill(0));
for (let i = 0; i < n; i++) dp[i][i] = 1;
for (let i = n - 2; i >= 0; i++) {
for (let j = i + 1; j <= n; j++) {
if (str[i] === str[j]) {
dp[i][j] = dp[i - 1][j - 1] + 2;
} else {
dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
}
}
}
return dp[0][n - 1];
}
longestPalindromeSubsequence("aecda");
子串
HJ63 DNA序列√(中级)
const line = readline();
const n = Number(readline());
const l = line.length;
let max = 0; // 最大出现数量(比例)
let result; // 输出的子串
for (let i = 0; i <= l - n; i++) {
const cut = line.slice(i, i + n); // 根据长度截取的子串
let timer = 0; // 初始化 GC 出现次数
for (let j of cut) {
if (j === "G" || j === "C") {
timer++;
}
}
if (timer > max) {
result = cut; // 更新输出的子串
max = timer; // 更新最大数量(比例)
}
}
console.log(result);