双指针排序

1,866 阅读1分钟

双指针查找:使用两个指针,一个遍历数组,一个指向需要操作的地方。直到遍历完数组。 双指针查找.png

1. 移除数组中的元素

给你一个数组 arr 和一个值 target,移除所有数值等于 target 的元素。要求在原数组删除。

解题思路

1.这个解决方式有很多,可以从后往前遍历,使用splice删除,可以使用正则替换删除。这里使用双指针来删除。
2.创建两个索引,一个遍历数组;一个指向需要改变的位置。
3.最后截取数组到需要改变的位置返回就是需要的数组。

function fn(arr, target) {
    let indexOne = 0;
    let indexTwo = 0;
    while (indexOne < arr.length){
        if(arr[indexOne] !== target){
            arr[indexTwo] = arr[indexOne];
            indexTwo ++;
        }
        indexOne ++;
    }
    return arr.slice(0, indexTwo);
}

console.log(fn([1,2,3,3,4,5,4,3,3,6], 3));

上面的写法还可以如下

function fn(arr, target) {
    let indexTwo = 0;
    for(let i=0;i<arr.length;i++){
        if(arr[i] !== target){
            arr[indexTwo] = arr[i];
            indexTwo ++;
        }
    }
    return arr.slice(0, indexTwo);
}

2. 给有序数组的平方排序

已知有序数组 [-4,-1,0,3,10],给每个值平方组成的数组排序。要求时间复杂度O(n)。

2-1. 解法1

思路
  1. 因为已知有序,那么复数部分平方后是单调递减。正数部分单独递增。
  2. 拆分为一个正数一个复数的数组,然后处理负数平方后颠倒和正数平方两个数组。
  3. 两个数组分别给个指针ab,从第一个开始。当a的值小于b的值,将a的值添加到结果数组,a+=1; 同理,b值更小时添加b的值,b+=1;相等你爱算那边就那边,无所谓。当两个数组都遍历完结束(我 这里是有一个遍历完将另一个剩余的添加进来,结束)
  4. 第一个函数是使用二分查找查到正负分界。二分查找可以看我另一篇介绍
function searSplit(arr) {
    let leftIndex = 0;
    let rightIndex = arr.length - 1;
    let middle;
    while (leftIndex <= rightIndex) {
        middle = Math.floor((leftIndex + rightIndex) / 2);
        if(leftIndex === rightIndex){
            return arr[middle] ===0 ? middle : leftIndex
        }
        if(0 > arr[middle]){
            leftIndex = middle + 1
        }else{
            rightIndex = middle
        }
    }
}


function fn(arr) {
    // 如果存在负数,找到分界点最右边小于0的数
    if (arr[0] < 0) {
        let splitIndex;
        splitIndex = searSplit(arr);
        let leftArr = arr.slice(0, splitIndex);
        leftArr.sort((a,b) => b-a);
        leftArr = leftArr.map(item => item * item);
        let rightArr = arr.slice(splitIndex);
        rightArr = rightArr.map(item => item * item);
        let leftIndex = 0;
        let rightIndex = 0;
        let result = []

        while (leftIndex <= leftArr.length - 1 || rightIndex <= rightArr.length - 1) {
            let leftVal = leftArr[leftIndex];
            let rightVal = rightArr[rightIndex];
            if(leftIndex>=leftArr.length){

                return result.concat(rightArr.slice(rightIndex))
            }
            if(rightIndex>=rightArr.length){
                console.log(leftIndex)
                return result.concat(leftArr.slice(leftIndex))
            }

            if(leftVal < rightVal){
                leftIndex ++
                result.push(leftVal)
            }else if(leftVal > rightVal ) {
                rightIndex ++;
                result.push(rightVal);
            }else{
                leftIndex ++;
                result.push(leftVal);
            }
        }

        return result;
    }
    return arr.map(item => item * item);
}

console.log(fn([-4, -1, 0, 3, 10]))

2-2. 解法二

思路

1.因为是个有序数组,那么每个平方后,前面部分是递减,后一部分是递增。 2.使用双指针,一个指向开始一个指向末尾。创建一个空数组用于存放最后的结果。 3.比较两个指正对应值得大小,大的unshift进数组,相应大的指针往中间移动。 4.不断重复上面,知道两个指针相等保存最后一个值停止。

function fn(arr) {
    arr = arr.map(item => item * item);
    let leftIndex = 0;
    let rightIndex = arr.length - 1;

    let result = [];
    while (leftIndex<=rightIndex){
        if(arr[leftIndex] > arr[rightIndex]){
            result.unshift(arr[leftIndex]);
            leftIndex++;
        } else{
            result.unshift(arr[rightIndex]);
            rightIndex--;
        }
    }
    return result
}

console.log(fn([-4,-1,1,3,10]));