主旨思想
分治思想主旨就是“分而治之”,大概就是指将一个规模较大的问题分割成规模较小的同类问题,然后再将这些小的子问题,逐个解决,最终大问题也就解决掉了。通常分治和递归是一起用的。
例题
二分法查找
二分法查找算法是一种提现分治思想的算法。 力扣题目链接:704. 二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/binary-search 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
二分法查找算法的思路的前提是数组有序的,将上面数组从中间一分为二,然后用中间middle 值和target 目标值进行比较:
- 如果中间的数大于
target 目标值,那么target 就可能在左边数组当中,然后把中间middle-1 赋值给右边right 的值,再从左边数组中寻找新的中间middle 值和target 目标值进行比较 - 如果中间的数小于
target 目标值,那么target 就在可能右边数组当中,然后把中间middle+1 赋值给左边left 的值,再从边数组中寻找新的中间middle 值和target 目标值进行比较
例如示例 1:中用图表示:
非递归写法
javascript:
var search = function(nums, target) {
let left = 0, right = nums.length-1;
while(left <= right)
{
let mid =left + Math.floor((right - left)/2);
if(nums[mid] > target)
{
right = mid - 1;
}
else if(nums[mid] < target)
{
left = mid + 1;
}
else
{
return mid;
}
}
return -1;
};
递归写法
C:
int recursion(int *nums, int target, int left, int right)
{
if(left > right)
{
return -1;
}
else
{
int mid = left + (right - left)/2;
if(target < nums[mid])
{
return recursion(nums, target, left, mid - 1);
}
else if(target > nums[mid])
{
return recursion(nums, target, mid + 1, right);
}
else
{
return mid;
}
}
}
int search(int* nums, int numsSize, int target){
int left = 0, right = numsSize - 1;
return recursion(nums, target, left, right);
}
快速排序算法
基本思想
快速排序用到了分而治之的思想。
- 先从数组中找到一个数,可以是是任取待排序序列的一个元素作为中心元素(可以用第一个,最后一个,也可以是中间任何一个),习惯将其称为
pivot 枢轴元素; - 用
pivot 将数组分成两个数组:
- 将所有小于
pivot 的数放在其左边; - 将所有大于
pivot 的数在其右边; - 然后对两个新的数组按照上面的算法继续排序。
例如: 数组 [ 21, 15, 34 , 10, -3, 1 , 16 , 44, 10, 49];
- 定义一枢轴元素
pivot ,即为21; - 定义一左边指针的为
left ; - 定义一右边指针的为right。
- 然后从右边往左边找比pivot小的数
- 把指针right所指的值赋值给left
直到 这样第一趟的排序就完成了,通过pivot 将数组分成了[10,15,16,10,-3,1] 与 [44, 34, 49]左右两部分,然后分别对这两个数组重新用相同的算法,直到只剩下一个元素。
代码
javascript:
function partition(arr, left, right) {
var pivot = arr[left];
while (left < right) {
while (left < right && arr[right] >= pivot) {
right--;
}
arr[left] = arr[right];
while (left < right && arr[left] <= pivot) {
left++;
}
arr[right] = arr[left];
}
arr[right] = pivot;
return right;
}
function quickSort(arr, left, right) {
var middle;
if (left < right) {
middle = partition(arr, left, right);
partition(arr, mid + 1, right);
partition(arr, left, mid - 1);
}
}
var arr = [ 21, 15, 34 , 10, -3, 1 , 16 , 44, 10, 49];
console.log("排序前的数组:", arr)
quickSort(arr, 0, arr.length - 1);
console.log("排序后的数组", arr);
时间和空间复杂度分析
时间复杂度:
- 理想的情况:时间复杂度为O(nlogn)
- 最坏情况:O(n2),这种情况是退化成冒泡排序
**空间复杂度:**根据实现的方式不同而不同 稳定性:不稳定
归并算法
基本思想
归并算法也是分而治之的思想(分治法) 。 例子 输入数组 [ 2, 5, 3 , 10, -3, 1 , 6 , 4]; 分治思想如下:
代码
function merge(arr, left, mid, right, temp) {
var i = left;
var j = mid + 1;
var t = 0;
while (i <= mid || j <= right) {
if (i > mid) {
temp[t++] = arr[j++];
}
else if (j > right) {
temp[t++] = arr[i++];
}
else {
if (arr[i] <= arr[j]) {
temp[t++] = arr[i++];
}
else {
temp[t++] = arr[j++];
}
}
}
var k = left;
t = 0;
while (k <= right) {
arr[k++] = temp[t++]
}
}
function mergeSort(arr, left, right, temp) {
if (left < right) {
var mid = Math.floor((left + right) / 2);
mergeSort(arr, left, mid, temp);
mergeSort(arr, mid + 1, right, temp);
merge(arr, left, mid, right, temp);
}
}
var arr = [2, 5, 3, 10, -3, 1, 6, 4];
var temp = new Array(arr.length);
console.log("排序前:", arr);
mergeSort(arr, 0, arr.length - 1, temp);
console.log("排序后:", arr);
|