剑指Offer | day12_双指针(快排那一套)

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


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


示例 :

输入: "  hello world!  "
输出: "world! hello"

说明:

  • 无空格字符构成一个单词。
  • 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
  • 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

方法:

  1. 处理空格
  2. 按格式输出
class Solution {
public:
    string reverseWords(string s) {
        vector<string> v;
        // 处理空格,原字符串后加一个空格更方便处理
        s += ' ';
        string str = "";
        for(char ch : s) {
            if(ch == ' ') {
                if(!str.empty()) {
                    v.push_back(str);
                    str.clear();
                }
            }
            else str += ch;
        }
        // 特殊情况
        if(v.empty()) return "";
		// 按格式输出字符串,注意最后一个输出的字符串不需要后接空格
        str.clear();
        for(int i = v.size() - 1; i > 0; i--) {
            str += v[i];
            str += ' ';
        }

        return str + v[0];
    }
};

c++写字符串的题就看这儿:

c++字符串模板



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


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


示例 :

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

限制:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^6

方法:二分查找(超时)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        
        for(int i = 0; i < nums.size()-1; i++) {
            int val = target - nums[i];
            int res = binary(nums, i+1, nums.size()-1, val);
            if(res != -1) {
                return {nums[i], nums[res]};
            }
        }
        return {};
    }
    int binary(vector<int> nums, int l, int r, int val) {
        
        if(l > r) return -1;

        int mid = l + ((r - l) >> 1);
        if(nums[mid] == val) {
            return mid;
        }
        else if(nums[mid] > val) {
            return binary(nums, l, mid-1, val);
        }
        else {
            return binary(nums, mid+1, r, val);
        }
    }
};
  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1)

方法:双指针(类似快排)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int l = 0;
        int r = nums.size()-1;
        
        while(l < r) {
            if(target == nums[l] + nums[r]) {
                return vector<int>{nums[l], nums[r]};
            }
            else if(target > nums[l] + nums[r]) {
                l++;
            }
            else if(target < nums[l] + nums[r]) {
                r--;
            }
        }
        return {};
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

二分查找的两种写法:

  • 递归
int binarySortRecursive(int num[], int l, int r, int val) {
	if (l > r) return -1;

	int mid = l + ((r - l) >> 1);
	if (num[mid] == val) {
		return mid;
	}
	else if (num[mid] > val) {
		return binarySortRecursive(num, l, mid - 1, val);
	}
	else {
		return binarySortRecursive(num, mid + 1, r, val);
	}
}

  • 非递归
int binarySort(int num[], int l, int r, int val) {

	while (l <= r) {
		int mid = l + ((r - 1) >> 1);
		if (num[mid] == val) {
			return mid;
		}
		else if (num[mid] > val) {
			r = mid - 1;
		}
		else {
			l = mid + 1;
		}
	}
	return -1;
}


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


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


示例:

输入:nums = [1,2,3,4]
输出:[1,3,2,4] 
注:[3,1,2,4] 也是正确的答案之一。

提示:

  1. 0 <= nums.length <= 50000
  2. 0 <= nums[i] <= 10000

方法:双指针

class Solution {
public:
    vector<int> exchange(vector<int>& nums) {
        int l = 0;
        int r = nums.size() - 1;

        while (l < r) {
            // 超级注意! && 右边的表达式一定要正确的添加括号,不然运算优先级会乱掉
            while (l < r && (nums[l]&1) == 1) {
                l++;
            }
            while (l < r && (nums[r]&1) == 0) {
                r--;
            }
            if (l < r) {
                int temp = nums[l];
                nums[l] = nums[r];
                nums[r] = temp;
                l++;
                r--;
            }
        }
        return nums;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

posted @ 2021-10-21 22:38  不是勇士  阅读(38)  评论(0)    收藏  举报