从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。简单的来说:给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: _permute(‘abc’)
输出: [ ‘abc’, ‘acb’, ‘bac’, ‘bca’, ‘cab’, ‘cba’ ]
通过图片可以得到,全排列的代码可以从两个维度进行分析:for循环横向遍历,递归纵向遍历
。for循环控制首位元素的获取,递归控制后续元素的获取,此处需要注意的是需要进行当前元素是否已经被获取
,同时使用一个数组进行数据的存储,当且仅当该数组的长度等于初始数组的长度时
,代表已找到一组结果,此时结束递归。
// 当获取的元素个数等于传入数组长度时(此时说明找到了一组结果)
if (path.length === k) {
// 将这组数据存进结果集数组
res.push(path);
// 结束递归
return;
}
那么如何进行当前元素是否已被使用的判断呢?可以使用一个used数组
,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次
。
const _permute = string => {
// 结果集数组
const res = [];
// 元素获取数组
let path = '';
// 调用backTracking函数
// 参数1:需要全排的数组 参数2:数组的长度 参数3:used数组记录当前元素是否已被使用
backTracking(Array.from(string), string.length, []);
// 返回最后的结果
return res;
// 递归函数
function backTracking(n, k, used) {
// 当获取的元素个数等于传入数组长度时(此时说明找到了一组结果)
if (path.length === k) {
// 将这组数据存进结果集数组
res.push(path);
// 结束递归
return;
}
for (let i = 0; i < k; i++) {
if (used[i]) continue; // 当前元素已被使用, 结束此次循环
path = path + n[i]; // 将符合条件的元素存进path数组
used[i] = true; // 并将该元素标为true,表示已使用同支
backtracking(n, k, used);
path = path.substring(0, path.length - 1)
used[i] = false;
}
}
};
console.log(_permute('abc'));
给定一个长度为 n 的数组,请你编写一个函数,返回该数组按升序排序后的结果。
要求:时间复杂度 O(n^2),空间复杂度 O(n)
进阶:时间复杂度 O(nlogn),空间复杂度 O(n)
注:本题数据范围允许绝大部分排序算法,请尝试多种排序算法的实现。
使用冒泡排序法实现,时间复杂度 O(n^2),空间复杂度 O(n)。
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型一维数组 待排序的数组
* @return int整型一维数组
*/
function MySort(arr) {
// write code here
for (let i = 0; i < arr.length - 1; i++) {
for (let j = i + 1; j < arr.length; j++) {
if(arr[j] < arr[i]) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
module.exports = {
MySort: MySort,
};
使用快速排序法实现,时间复杂度 O(nlogn),空间复杂度 O(n)。
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型一维数组 待排序的数组
* @return int整型一维数组
*/
function MySort(arr) {
// write code here
QuickSort(arr, 0, arr.length - 1);
return arr;
}
// 快速排序设计
function QuickSort(arr, s, t) {
let left = s + 1,
right = t,
x = arr[s];
while (left <= right) {
while (left <= right && arr[left] <= x) left++;
while (left <= right && arr[right] >= x) right--;
if (left < right) {
let temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
if (s != right) {
arr[s] = arr[right];
arr[right] = x;
}
// 不同情况下的递归调用
if (s < right - 1) QuickSort(arr, s, right - 1);
if (right + 1 < t) QuickSort(arr, right + 1, t);
}
module.exports = {
MySort: MySort,
};
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
示例
输入:[3,2,4],6
返回值:[2,3]
说明:因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以返回[2,3]。
最开始想到的算法是使用一个for循环控制数组使用includes()方法判断是否存在target - numbers[i]的值,若存在则使用break结束循环,反之则继续寻找。不出意外的超时了。
/**
*
* @param numbers int整型一维数组
* @param target int整型
* @return int整型一维数组
*/
function twoSum(numbers, target) {
// write code here
let result = [];
for (let i = 0; i < numbers.length; i++) {
// 先得到目标变量和当前数组变量的差值
let num = target - numbers[i];
// 使用includes进行差值是否存在于数组判断
if (numbers.includes(num)) {
let index = numbers.indexOf(num);
if (index != i) {
result.push(i + 1);
result.push(index + 1);
break;
} else {
continue;
}
}
}
return swap(result);
}
function swap(arr) {
if (arr[0] > arr[1]) {
let temp = arr[0];
arr[0] = arr[1];
arr[1] = temp;
}
return arr;
}
module.exports = {
twoSum: twoSum,
};
通过对上传代码的阅读,发现使用Map.has()哈希判断可以减少时间复杂度。
/**
*
* @param numbers int整型一维数组
* @param target int整型
* @return int整型一维数组
*/
function twoSum(numbers, target) {
// write code here
const res = new Array(2);
let map = new Map(),
len = numbers.length;
for (let i = 0; i < len; i++) {
if (map.has(target - numbers[i])) {
res[0] = map.get(target - numbers[i]) + 1;
res[1] = i + 1;
break;
} else {
map.set(numbers[i], i);
}
}
return res;
}
module.exports = {
twoSum: twoSum,
};
有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。
给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。
要求:时间复杂度 O(nlogn),空间复杂度 O(1)。
示例
输入:
[1,3,5,2,2],5,3
返回值:2
由题目我们可以根据快速排序的思路(以升序为例),其原理是先选取一个基准数据x,初始化左left右right指针变量,若left指针指向的数据小于等于基准数据x,则left向右移动,当指针指向的数据大于x时,left停止移动。相同的,right指针就是进行大于等于x的判断,同时left<=right是外层循环的执行条件。
while(left <= right) {
while(left <= right && arr[left] >= x) left++;
while(left <= right && arr[right] <= x) right--;
if(left < right) {
let t = arr[left];
arr[left] = arr[right];
arr[right] = t;
}
}
同时使用right与k进行结果返回的判断,当right === k - 1时即找到第K大的数据,当right > k - 1时到right指针指向数据的左边寻找,right < k - 1时到right指针指向数据的右边去找。以此重复循环直到结果出现。
if(right == k -1) {
return arr[right];
} else if(right > k - 1) {
return QuickSort(arr, s, right - 1, k);
} else {
return QuickSort(arr, right + 1, t, k);
}
/**
*
* @param a int整型一维数组
* @param n int整型
* @param K int整型
* @return int整型
*/
function findKth( a , n , K ) {
// write code here
return QuickSort(a, 0, n - 1, K)
}
function QuickSort(arr, s, t, k) {
let left = s + 1, right = t, x = arr[s];
while(left <= right) {
while(left <= right && arr[left] >= x) left++;
while(left <= right && arr[right] <= x) right--;
if(left < right) {
let t = arr[left];
arr[left] = arr[right];
arr[right] = t;
}
}
if(s != right) {
arr[s] = arr[right];
arr[right] = x;
}
if(right == k -1) {
return arr[right];
} else if(right > k - 1) {
return QuickSort(arr, s, right - 1, k);
} else {
return QuickSort(arr, right + 1, t, k);
}
}
module.exports = {
findKth : findKth
};
给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。
输入:[4,5,1,6,2,7,3,8],4
返回值:[1,2,3,4]
说明:返回最小的4个数即可,返回[1,3,2,4]也可以
观察可以发现,只需要将数组进行排序,再使用一个for循环进行数据的输出即可。为了简便,直接使用内置的方法进行排序。
input.sort((a, b) => {
return a - b;
});
function GetLeastNumbers_Solution(input, k) {
// 将传进的数组进行排序
input.sort((a, b) => {
return a - b;
});
// 初始化结果数组变量
let res = [];
// 将结果存进res数组中
for (let i = 0; i < k; i++) {
res.push(input[i]);
}
// 返回结果
return res;
}
module.exports = {
GetLeastNumbers_Solution: GetLeastNumbers_Solution,
};
请补全JavaScript代码,要求以Boolean的形式返回第一个实例参数是否在第二个函数参数的原型链上。
由于只看过原型和原型链的讲解视频,并没有进行对应的知识实践,做开始即使是看了题解也不是很明白代码表达的意思。最后通过代码理解,知识回顾等进行代码设计。
附上原型和原型链的关系图。
对对象原型和原型链有了更深的理解。
const _instanceof = (target, Fn) => {
// 先判断传进的target是否为一个对象
if(typeof target !== 'object' || target === null) return false;
// 获取target对象中的对象原型__proto__
let proto = target.__proto__;
// 使用while循环逐层向上寻找__proto__
while(proto) {
// 当符合条件返回结果true
if(proto === Fn.prototype) return true;
// 不断向上寻找,直到找到结果或null
proto = proto.__proto__;
}
return false;
}