最近准备面试,在lintcode上刷了些简单和中级的算法题,也掌握了一些常用的算法,由于我目前只会js相关的语法,所以解法都是我自己用js去解的,在此留个坑纪念一下,希望能帮到和我一样的初学者或者是同行者。
最大子数组
常规暴力算法 -- 易于理解,复杂度O(n^3)
/**
* 给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。
*
* @param nums: A list of integers
* @return: A integer indicate the sum of max subarray
*/
const maxSubArray = function(nums) {
var l = nums.length;
var ans = -10000; //初始化值
for (var i = 0; i < l; i++) {
for (var j = i; j < l; j++) {
let sum = 0;
for (var k = i; k < j; k++) {
sum += nums[k];
}
if (sum > ans) {
ans = sum;
}
}
}
return ans;
}
/* 暴力枚举出所有子集合 复杂度n^3 */
let num = [-2, 2, -3, 4, -1, 2, 1, -5, 3]
console.log(maxSubArray(num));
贪心算法 --- 丢弃子串和为负数的子串,只保留正子串O(n)
function maxSubArray1(nums) {
var l = nums.length;
var ans = -10000;
var sum = 0;
for (var i = 0; i < l; i++) {
sum += nums[i];
if (sum > ans) {
ans = sum;
}
if (sum < 0) {
sum = 0; // 子串和为负数,丢掉
}
}
return ans
}
寻找主元素
/**
* 给定一个整型数组,找到主元素,它在数组中的出现次数严格大于数组元素个数的1/k。
* 数组只有唯一主元素
*
* @param nums: A list of integers
* @param k: An integer
* @return: The majority number
*/
const majorityNumber = function(nums, k) {
var i, l = nums.length,
obj = {};
var temp = ~~(l * 1 / k); // 中间数
for (i = 0; i < l; i++) {
if (nums[i] in obj) {
obj[nums[i]] += 1;
} else {
obj[nums[i]] = 1;
}
// 因为是唯一主元素
if (obj[nums[i]] > temp) {
return nums[i];
}
}
}
搜索二维矩阵
/**
* 搜索二维矩阵
*
* 复杂度O(log(n)) + O(log(m))
*
* @param matrix: matrix, a list of lists of integers
* @param target: An integer
* @return: a boolean, indicate whether matrix contains target
*/
const searchMatrix = function(matrix, target) {
var row = 0;
if (matrix.length === 0) {
return false;
}
for (var i = 0; i < matrix.length; i++) {
let last = matrix[i].pop()
if (last < target) {
continue;
} else if (last === target) {
return true;
} else {
row = i;
break;
}
}
for (var j = 0; j < matrix[row].length; j++) {
if (matrix[row][j] === target) {
return true;
} else {
continue;
}
}
return false;
}
搜索二维矩阵 II
/**
* 搜索二维矩阵 II
*
* 写出一个高效的算法来搜索m×n矩阵中的值,返回这个值出现的次数。
* 每行中的整数从左到右是排序的。
* 每一列的整数从上到下是排序的。
* 在每一行或每一列中没有重复的整数。
*
* @param matrix: A list of lists of integers
* @param target: An integer you want to search in matrix
* @return: An integer indicate the total occurrence of target in the given matrix
*/
const searchMatrix1 = function(matrix, target) {
var i, l = matrix.length,
num = 0;
for (i = 0; i < l; i++) {
var row = matrix[i];
var j, jl = row.length;
for (j = 0; j < jl; j++) {
if (row[j] === target) {
num += 1;
break;
}
}
}
return num;
}
寻找第K大个数
/**
* 寻找第K大个数
*
* @param n: An integer
* @param nums: An array
* @return: the Kth largest element
*/
const kthLargestElement = function(n, nums) {
if (n === 1) {
return Math.max.apply(null, nums);
}
let i,
l = nums.length,
left = [],
right = [],
pivot = nums[~~(Math.random() * l)];
for (i = 0; i < l; i++) {
if (nums[i] > pivot) {
right.push(nums[i])
} else {
left.push(nums[i])
}
}
if (right.length > n) {
return kthLargestElement(n, right);
} else if (right.length === n) {
return Math.min.apply(null, right);
} else {
n = n - right.length;
return kthLargestElement(n, left);
}
}
console.log(kthLargestElement(10, [1, 2, 3, 4, 5, 6, 8, 9, 10, 7])); // 1
console.log(kthLargestElement(4, [9, 3, 2, 4, 8])); // 3
/**
* 给定一个整型数组,找到主元素,它在数组中的出现次数严格大于数组元素个数的1/k。
* 数组只有唯一主元素
*
* @param nums: A list of integers
* @param k: An integer
* @return: The majority number
*/
const majorityNumber = function(nums, k) {
var i, l = nums.length,
obj = {};
var temp = ~~(l * 1 / k); // 中间数
for (i = 0; i < l; i++) {
if (nums[i] in obj) {
obj[nums[i]] += 1;
} else {
obj[nums[i]] = 1;
}
// 因为是唯一主元素
if (obj[nums[i]] > temp) {
return nums[i];
}
}
}
console.log(majorityNumber([3, 1, 2, 3, 2, 3, 3, 4, 4, 4], 3));
贪心问题:
钱币找零问题
假设有数目不限的面值为20,10,5,1的硬币。 给出需要找零数,求出找零方案,要求:使用数目最少的硬币
策略:每次选取可供钱币的最大值
/* m 为可供找零的面值倒序数组 eg.[20,10,5,1] n为找零数 */
function greedyMoney(m, n) {
let result = [];
for (var i = 0; i < m.length; i++) {
while (n >= m[i] && n > 0) {
result.push(m[i])
n = n - m[i];
}
}
return result;
}
小船过河问题
只有一艘船,能乘2人,船的运行速度为2人中较慢一人的速度,过去后还需一个人把船划回来,问把t个人运到对岸,最少需要多久 假设t个人的速度按升序排列。
策略
- 最快的和次快的过河,然后最快的将船划回来;次慢的和最慢的过河,然后次快的将船划回来,所需时间为:t[0]+2*t[1]+t[n-1]。
- 最快的和最慢的过河,然后最快的将船划回来,最快的和次慢的过河,然后最快的将船划回来,所需时间为:2*t[0]+t[n-2]+t[n-1]。
- 每次运行不影响他人,所以具有贪心子结构。解法如下
let array = [1, 2, 3, 4, 5, 6, 7, 9, 12, 15] // 10个人,每个人过河花费时间对应为1,2,...n
function greedyBoat(arr) {
let total = 0; // 总用时
while (arr.length > 0) {
var l = arr.length;
// 如果人数剩余3人
if (l === 3) {
total += arr[0] + arr[1] + arr[2];
break;
}
// 如果人数剩余2人
if (l === 2) {
total += arr[1];
break;
}
// 如果人数剩余1人
if (l === 1) {
total += arr[0];
break;
}
// 一次过河用时
total += Math.min.apply(null, [arr[l - 1] + 2 * arr[0] + arr[l - 2], arr[0] + 2 * arr[1] + arr[l - 1]])
// 同时去除数组末尾两个数字
arr.length -= 2;
}
return total;
}
console.log(greedyBoat(array));