起手诗
迎着晨风想一想,今天该如何努力
踏着夕阳问一问,今天有什么收获
从今天起,从零开始学算法,不忘初心,继续前进
I hava a drame 从算法小白,一步步走向大神
做人就是敢吹牛,牛逼的人就是吹完牛,像牛一样工作!!!
第一天 【2020-03-31】
给定一个仅包含数字 2-9的字符串,返回所有它能表示的字母组合。 给出数字与电话按键相同。注意 1 不对应任何字母。
/*电话号码的组合*/
function phone(str){
// 建立电话号码键盘映射
let map = ['', 1, 'abc', 'def', 'ghi', 'jkl',
'mno', 'pqrs', 'tuv', 'wxyz'],
// 把输入字符串按单字符分割变成数组 234 => [2,3,4]
num = str.split(''),
// 保存键盘映射后的字母内容 , 如 23 => ['abc','def']
code = []
num.forEach(item => {
if (map[item]) {
code.push(map[item])
}
})
let comb = (arr) => {
// 临时变量用来保存前两个组合的结果
let tmp = []
// 最外层的循环剩遍历第一个元素里层的循环是遍历第二个元素
for (let i = 0, il = arr[0].length; i < il; i++) {
for (let j = 0, jl = arr[1].length; j < jl; j++) {
tmp.push(`${arr[0][i]}${arr[1][j]}`)
}
}
arr.splice(0, 2, tmp);
if (arr.length > 1) {
comb(arr)
} else {
return tmp;
}
return arr[0];
}
return comb(code)
}
console.log(phone("23"))
[
'ad', 'ae', 'af',
'bd', 'be', 'bf',
'cd', 'ce', 'cf'
]
第二天 【2020-4-1】
nums包含从0到n的所有整数,但其中缺失了一个。请编写代码找出那个缺失的整数。
var missingNumber = function (nums) {
let arr = [];
let brr = [];
//计数器
let count = 0;
// =>从小到大排序
nums = nums.sort((A, B) => A - B)
//=>找出数组中的最大值
let maxNum = Math.max.call(null, ...nums);
for (let i = 0; i <= maxNum; i++) {
if (i <= maxNum) {
arr.push(i);
}
}
//=>arr =>从小到大的完整数组
for (let i = 0; i < arr.length; i++) {
if (nums.includes(arr[i])) {
count++;
//=>说明,两个数组完全相同
if (count === arr.length) {
//=>如果两个数组一样,则返回传递进来数组的长度
return nums.length;
}
} else {
//=> arr[i]=>缺失的整数
brr.push(arr[i])
}
}
return brr //=>以一个数组的形式,返回缺失的数字
};
第三天 【2020-4-2】
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
var removeElement = function (nums, val) {
<!--获取数组的长度-->
let ans = nums.length;
for (let i = 0; i < ans;) {
//=>如果当前项 = 查找的那一项
if (nums[i] == val) {
//=>把最后一项,赋值给当前项,再把最后一项他给删了
nums[i] = nums[ans - 1];
ans--;
} else {
//=>如果没找到,i++ 走循环,判断下一项
i++;
}
}
return ans;
};
console.log(removeElement([0, 1, 2, 2, 3, 0, 4, 2], 2));
//=> 5
第四天 【2020-4-3】
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值
不存在数组中,返回它将会被按顺序插入的位置
<!--一开始老想转换成字符串,其实这样不仅麻烦,而且还让面试官感到LOU-->
var searchInsert = function(nums, target) {
<!--先循环出每一项-->
for (let i = 0; i < nums.length; i++) {
<!--目标值和数组的每一项都不相等-->
if (nums[i] !== target) {
if(target > nums[nums.length - 1]){
return nums.length
}else{
<!--如果目标值小于数组的某一项,直接返回当前项的索引-->
<!--
首先还是要分析好逻辑,我一开始想用splice插入
然后转换成字符串,然后获取索引了,太麻烦.
-->
if (target < nums[i]) {
return i
}
}
}else{
<!--目标值和数组中的某一项相等,直接返回对应的索引-->
return nums.indexOf(target)
break;
}
}
};
第五天 【2020-4-6】
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
let maxSubArray = function(nums) {
<!--首先取出数组的第一项-->
let item = nums[0];
let sum = 0;
<!--对数组进行遍历-->
for(const num of nums) {
if(sum > 0) {
sum += num;
} else {
sum = num;
}
<!--上一次计算的结果,都和sum进行比对并取出最大值-->
item = Math.max(item, sum);
}
<!--最后返回最大子序列的和-->
return item;
};
第六天 【2020-4-7】
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
var isPalindrome = function (x) {
<!--考虑边界case和正常case-->
if (x < 0 || (x % 10 === 0 && x !== 0)) {
return false;
}
<!--~ 按位非(反转操作数的比特位,即0变成1,1变成0)。-->
<!--写两个主要是为了去除小数点后面的数字-->
let rev = 0;
while (rev < x) {
rev = rev * 10 + x % 10;
x = ~~(x / 10);
}
<!--分别是考虑的奇数情况和偶数情况-->
return (rev === x) || (~~(rev / 10) === x)
};
console.log(isPalindrome(121))
第七天 【2020-7-6】
如何格式化成美元的格式
function formateValue(num) {
if (!num) return;
// 先将数值取两位小数
let str = (Math.round(num * 100) / 100).toString();
// 找到小数点的下标
let pointIdx = str.indexOf(".");
// 如果没有小数点
if (pointIdx < 0) {
// 将数值进行千位符转换
str = str.replace(/(\d)(?=(?:\d{3})+$)/g, "$1,");
// 添加小数点
pointIdx = str.length;
str += ".";
while (str.length <= pointIdx + 2) {
str += "0";
}
} else {
// 如果有小数点
// 取整数部分, 也可以用 parseInt
let int = str.substr(0, pointIdx);
// 整数部分进行千位符转换
int = int.replace(/(\d)(?=(?:\d{3})+$)/g, "$1,");
str = int + str.substr(pointIdx);
while (str.length <= pointIdx + 3) {
str += "0";
}
}
return "US$" + str;
}
第八天 【2020-7-14】
要求返回数组中属性值最大的对象
let list = [{ name: '11' }, { sex: '22' }, { age: "33" }]
let obj = {};
let otherObj = {};
list.map((item => {
Object.assign(obj, item)
}))
let val = Math.max.apply(Math, Object.values(obj));
let keys = Object.keys(obj);
for(let i = 0;i<keys.length;i++){
let item = keys[i];
if(obj[item] == val){
return otherObj[item] = val
}
}
<!--写完这个的时候还遇到一个小问题 ,我之前return的时候是这样写的:
return {item:obj[item]}==>{item:33},后来一想,肯定不行啊
这是对象,对象是heap(堆),肯定不会像上级作用域查找啊-->
第九天 【2021-3-8】
判断括号是否合法
/* 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
* 有效字符串需满足:
* 左括号必须用相同类型的右括号闭合。
* 左括号必须以正确的顺序闭合。
* (输入: "()"
* 输出: true
* 输入: "([)]"
* 输出: false
*/
let isValid = function (s) {
if (s == " " || s == "") {
return true;
}
let stack = [];
let left = ["{", "(", "["];
let right = ["}", ")", "]"];
for (let i = 0; i < s.length; i++) {
if (left.indexOf(s[i]) > -1) {
stack.push(s[i]);
} else if (s[i] === " ") {
continue;
} else {
if (stack.pop() != left[right.indexOf(s[i])]) {
return false;
}
}
}
if (stack.length != 0) {
return false;
}
return true;
};
console.log(isValid("[(])"))
第十天 【2021-3-9】
身高问题
/**
* 获取队中从前到后每个人与前方身高高于自己的人的最短距离
* @param height int整型一维数组 队中从前到后每个人与前方身高高于自己的人的最短距离
* @return int整型一维数组
*/
function DistanceToHigher(height) {
let arr = [0];
for (let i = 0; i < height.length; i++) {
}
// 0 1 2 1 0 1
let a = [175, 173, 174, 163, 182, 177];
console.log(DistanceToHigher(a))
排序算法在总结
冒泡排序
- 第一项和第二项相比,如果大于第二项则互换位置,每次循环完成一遍都会把最大的值放到数组的最后一个 所以内层循环为了不再重复比较,一定要 -i
function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len - 1; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) { // 相邻元素两两对比
var temp = arr[j+1]; // 元素交换
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
插入排序
- 会打牌就会插入排序
function insert(A, i, x) {
let p = i - 1;
while (p >= 0 && A[p] > x) {
A[p + 1] = A[p];
p--;
}
A[p + 1] = x;
}
function insert_sort(A) {
for (let i = 1; i < A.length; i++) {
insert(A, i, A[i]);
}
return A
}
console.log(insert_sort([3,2,1]));
// 3,2,1
// 3,3,1 ===> 2,3,1
// 2,3,3 ===> 2,2,3===>1,2,3
归并排序
- 自顶向下
function merge(A, p, q, r) {
let A1 = A.slice(p, q);
let A2 = A.slice(q, r);
A1.push(Number.MAX_SAFE_INTEGER);
A2.push(Number.MAX_SAFE_INTEGER);
for (let k = p, i = 0, j = 0; k < r; k++) {
A[k] = A1[i] < A2[j] ? A1[i++] : A2[j++];
}
}
function merge_sort(A, p, r) {
if (r - p < 2) {
return;
}
const q = Math.ceil((p + r) / 2);
merge_sort(A, p, q);
merge_sort(A, q, r);
merge(A, p, q, r);
}
const arr = [3, 2, 1];
merge_sort(arr, 0, arr.length);
#### 选择排序
- **假设法**
```js
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) { // 寻找最小的数
minIndex = j; // 将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
计数排序
- 先统计数组中每个数出现了多少次,放到对应的数组下标中
function countingSort(arr) {
let maxValue = Math.max(arr)
let bucket = new Array(maxValue+1),
sortedIndex = 0;
arrLen = arr.length,
bucketLen = maxValue + 1;
for (let i = 0; i < arrLen; i++) {
if (!bucket[arr[i]]) {
bucket[arr[i]] = 0;
}
bucket[arr[i]]++;
}
for (let j = 0; j < bucketLen; j++) {
while(bucket[j] > 0) {
arr[sortedIndex++] = j;
bucket[j]--;
}
}
return arr;
}
基数排序
function radix_sort(arr) {
// 取最大值 最大值的位数就是要循环遍历的次数
const max = Math.max(...arr);
// 定义一个桶
const buckets = Array.from({ length: 10 }, () => []);
// 定义当前要遍历的位数 个位 十位 百位...
let m = 1;
while (m < max) {
// m < 最大值
// 下方m要 m*=10 -> 每次遍历增加一位
// 保证遍历完所有可能的位数
// 放入桶
arr.forEach(number => {
// digit表示某位数的值
const digit = ~~((number % (m * 10)) / m);
// 把该位数的值放到桶buckets中
// 通过索引确定顺序 类比计数排序
buckets[digit].push(number);
});
// 从桶buckets中取值
// 完成此步后 就完成了一次位数排序
let ind = 0;
buckets.forEach(bucket => {
while (bucket.length > 0) {
// shift从头部取值
// 保证按照队列先入先出
arr[ind++] = bucket.shift();
}
});
// 每次最外层while循环后m要乘等10
// 也就是要判断下一位 比如当前是个位 下次就要判断十位
m *= 10;
}
}
桶排序
function countingSort(arr) {
let maxValue = Math.max(arr)
let bucket = new Array(maxValue+1),
sortedIndex = 0;
arrLen = arr.length,
bucketLen = maxValue + 1;
for (let i = 0; i < arrLen; i++) {
if (!bucket[arr[i]]) {
bucket[arr[i]] = 0;
}
bucket[arr[i]]++;
}
for (let j = 0; j < bucketLen; j++) {
while(bucket[j] > 0) {
arr[sortedIndex++] = j;
bucket[j]--;
}
}
return arr;
}
function bucketSort(arr, bucketSize) {
if (arr.length === 0) {
return arr;
}
let i;
let minValue = arr[0];
let maxValue = arr[0];
for (i = 1; i < arr.length; i++) {
if (arr[i] < minValue) {
minValue = arr[i]; // 输入数据的最小值
} else if (arr[i] > maxValue) {
maxValue = arr[i]; // 输入数据的最大值
}
}
// 桶的初始化
bucketSize = (maxValue - minValue)/arr.length +1
let bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;
let buckets = new Array(bucketCount);
for (i = 0; i < buckets.length; i++) {
buckets[i] = [];
}
// 利用映射函数将数据分配到各个桶中
for (i = 0; i < arr.length; i++) {
buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
}
arr.length = 0;
for (i = 0; i < buckets.length; i++) {
// 对每个桶进行排序,这里使用了插入排序
for (let j = 0; j < buckets[i].length; j++) {
arr.push(buckets[i][j]);
}
}
return arr;
}
console.log(bucketSort([8,7,3,3,18]));