1.搜索旋转排序数组(分治法)
题目描述:
已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。
在传递给函数之前,nums 在预先未知的某个下标 k(0<=k < nums.length)上进行了 旋转 , 使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。
例如, [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4]。
给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。
如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false 。
你必须尽可能减少整个操作步骤。
示例 1: 输入:nums=[ 2,5,6,0,0,1,2], target=0 输出:true
示例 2: 输入:nums=[ 2,5,6,0,0,1,2], target=3 输出:false
<script>
var search = function(nums, target) {
const n = nums.length;
if (n === 0) {
return false;
}
if (n === 1) {
return nums[0] === target;
}
let l = 0,
r = n - 1;
while (l <= r) {
const mid = Math.floor((l + r) / 2);
if (nums[mid] === target) {
return true;
}
if (nums[l] === nums[mid] && nums[mid] === nums[r]) {
++l;
--r;
} else if (nums[l] <= nums[mid]) {
if (nums[l] <= target && target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[n - 1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return false;
};
</script>
2.查找区间
题目描述:
给定一个增序的整数数组和一个值,查找该值第一次和最后一次出现的位置。
输入输出样例:
输入是一个数组和一个值,输出为该值第一次出现的位置和最后一次出现的位置(从 0 开始);如果不存在该值,则两个返回值都设为-1。
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
<script>
const binarySearch = (nums, target, lower) => {
let left = 0,
right = nums.length - 1,
ans = nums.length;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (nums[mid] > target || (lower && nums[mid] >= target)) {
right = mid - 1;
ans = mid;
} else {
left = mid + 1;
}
}
return ans;
}
var searchRange = function(nums, target) {
let ans = [-1, -1];
const leftIdx = binarySearch(nums, target, true);
const rightIdx = binarySearch(nums, target, false) - 1;
if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] === target && nums[rightIdx] === target) {
ans = [leftIdx, rightIdx];
}
return ans;
};
</script>
3.数组中的第K个最大元素
题目描述:
在一个未排序的数组中,找到第 k 大的数字。
输入输出样例: 输入一个数组和一个目标值 k,输出第 k 大的数字。题目默认一定有解。
Input: [3,2,1,5,6,4] and k = 2 Output: 5
要求:排序自己实现,排序方法要求使用“快速选择”
<script>
var findKthLargest = function(nums, k) {
nums.sort((a, b) => b - a) //降序排序
for (var i = 0; i < nums.length; i++) {
if ((k - 1) == i) { //i从0开始
return nums[i]
}
}
};
/* var findKthLargest = function(nums, k) {
// 快速排序
function sort(nums, Left, Right) {
let l = Left;
let r = Right;
let pivot = nums[l];
if (l >= r) return;
while (l < r) {
while (nums[r] >= pivot && l < r) {
r--;
}
if (nums[r] < pivot) {
nums[l] = nums[r];
l++;
}
while (nums[l] <= pivot && l < r) {
l++;
}
if (nums[l] > pivot) {
nums[r] = nums[l];
r--;
}
if (l === r) {
nums[l] = pivot
}
}
sort(nums, Left, l - 1);
sort(nums, r + 1, Right);
}
sort(nums, 0, nums.length - 1);
nums
return nums.reverse()[k - 1]
};
*/
const nums = [3, 2, 1, 5, 6, 4];
const k = 2;
console.log(findKthLargest(nums, k));
</script>
4.颜色分类
题目描述:
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1]
输出:[0,1,2]
提示:
n == nums.length
1 <= n <= 300
nums[i] 为 0、1 或 2
要求:
1.不使用代码库中的排序函数
2.使用常数空间的一趟扫描完成
一个直观的解决方案是使用计数排序的两趟扫描算法。
首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
你能想出一个仅使用常数空间的一趟扫描算法吗?
思路
这道题的解题其实就只是把0放在最前面,把2放在最后面,把1放在中间,其实一个排序就可以完成了,但是因为数组中只有三个值,所以我们可以使用三指针的方式,用O(n)的时间复杂度就完成了
三个指针分别指向
当前已知0放置在最右边的下标 left
当前已知1放置在最左边的下标 right
当前正在遍历的下标 index
遍历的时候有三种情况
当遍历到的数为0的时候,判断当前的index和left是否相同,如果相同,就直接将两个下标自增,如果不同,就将两个下标对应的值交换,然后left自增
当遍历到的数为1的时候,index自增
当遍历到的数为2的时候,index和right两个下标对应的数值交换,然后right自减
结束条件
left>=right
index>right
<script>
var sortColors = function(nums) {
let left = 0;
let right = nums.length - 1;
let index = 0;
let swap;
while (left < right && index <= right) {
if (nums[index] === 0) {
if (index !== left) {
swap = nums[left];
nums[left] = nums[index];
nums[index] = swap;
} else {
index++;
}
left++;
} else if (nums[index] === 1) {
index++;
} else {
swap = nums[right];
nums[right] = nums[index];
nums[index] = swap;
right--;
}
}
return nums;
};
const nums = [2, 0, 2, 1, 1, 0];
console.log(sortColors(nums));
</script>