算法打卡第十三天

147 阅读2分钟
  1. 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
  2. 剑指 Offer 57. 和为s的两个数字
  3. 剑指 Offer 58 - I. 翻转单词顺序

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。

题意理解 将数组排序奇数在前,偶数在后

  1. 使用双指针法,从数组开头l和结尾r开始遍历
  2. l,r均为索引,当l< r时循环急需,当nums[l]为基数时,l++;当nums[r]为基数时,r--;然后交换nums[r]和nums[l]的位置
  3. 直到循环结束

示例 输入:nums = [2, 7, 11, 15], target = 9 输出:[2, 7] 或者 [7, 2]

function exchange(nums) {
    // 暴力
    // const arr = []
    // nums.forEach(item => {
    //     console.log( item % 2 ===0 );
    //     if (item % 2 === 0) {
    //         arr.push(item)
    //     }else{
    //         arr.unshift(item)
    //     }
    // })
    // return arr

    // filter
    // const arr1 = nums.filter(item=>item%2===1)
    // const arr2 = nums.filter(item=>item%2===0)
    // return [...arr1,arr2]

    // 双指针
    let l = 0,
        r = nums.length - 1;
    while (l < r) {
        while (l < r && (nums[l] % 2 === 1)) {
            l++
        }
        while (l < r && (nums[l] % 2 === 0)) {
            r--
        }
        [nums[l], nums[r]] = [nums[r], nums[l]]
        // 或者
        // let current = nums[r]
        // nums[r] = nums[l]
        // nums[l] = current
    }
    return nums
}

剑指 Offer 57. 和为s的两个数字

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

提议理解 找出数据中两个数和为target的任意一对数字

  1. 暴力法超出时长,哈希慢,双指针最佳
  2. 一种标出数组是有序的这个很重要
  3. 这样就可以使用双指针,nums[left] + nums[right] === target,返回[nums[left], nums[right] ];nums[left] + nums[right] < target,则left++;nums[left] + nums[right] > target 则right --;
  4. 循环条件left < right

示例 输入:nums = [10, 26, 30, 31, 47, 60], target = 40 输出:[10, 30] 或者 [30, 10]

function twoSum(nums, target) {
    // 暴力
    // for (let i = 0; i < nums.length; i++) {
    //     const current = target - nums[i]
    //     if (nums.lastIndexOf(current)!==-1  && nums.lastIndexOf(current) !== i) {
    //         return [nums[i], current]
    //     }
    // }
    // return []

    // Map
    // let map = new Map()
    // for (let i = 0; i < nums.length; i++) {
    //     map.set(nums[i], i)
    // }
    // for (let i = 0; i < nums.length; i++) {
    //     if(map.has(nums[i]) && map.has(target - nums[i])){
    //         return [nums[i],target - nums[i]]
    //     }
    // }
    // return []

    // 双指针 最佳
    let l = 0,
        r = nums.length - 1;
    while (l < r) {
        if (nums[l] + nums[r] === target) {
            return [nums[l], nums[r]]
        } else if (target < nums[l] + nums[r]) {
            r--
        } else {
            l++
        }
    }
    return []
}

剑指 Offer 58 - I. 翻转单词顺序

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。

题意理解 翻转字符串,只反转字符串中单词的顺序,整个单词顺序不变,且反转后去句子两边空格,单词之间只有一个空格

  1. 双指针法,及r表示遍历当前单词的结尾,表示上个这个单词的开始
  2. 循环条件为l>=0
  3. 由于遍历原则,l会指向次单词的上个空格,所以字符截取时需要使用l+1,截取完后去除前面的空格,r-l;最后再去除句子开头结尾的空格

本人测试单项比多项块一点 示例 输入:s = "the sky is blue" 输出:"blue is sky the"

function reverseWords(s) {
    // 双指针
    // s = s.trim();
    // let l = r = s.length - 1
    // let arr = "";
    // while (r >= 0) {
    //     while (l >= 0 && s[l] !== " ") {
    //         l--;
    //     }
    //     arr += " " + s.slice(l + 1, r + 1)
    //     while (s[l] === " ") {
    //         l--
    //     }
    //     r = l;
    // }
    // return arr.trim()

    // 单项遍历
    s = s.trim();
    let right = s.length - 1;
    let str = ""
    while (right >= 0) {
        let wordLength = 0;
        while (right >= 0 && s[right] !== " ") {
            wordLength++;
            right--;
        }
        str += " " + s.substr(right + 1, wordLength)
        while (right >= 0 && s[right] === " ") {
            right--;
        }
    }

    return str.trim()
}