LeetCode 131.Palindrome Partitioning

78 阅读1分钟

LeetCode 131.Palindrome Partitioning

题目

Given a string s, partition s such that every substring of the partition is a palindrome . Return all possible palindrome partitioning of s.

题意

给定一个字符串,将其分割成若干个回文串,返回所有可能的分割方案。

示例

示例1

Input: "aab"
Output:
[
  ["aa","b"],
  ["a","a","b"]
]

示例2

Input: "a"
Output:
[
  ["a"]
]

分析

  1. 回溯法,递归求解。
  2. 递归函数的参数为字符串s和当前分割方案的起始位置cur
  3. 递归函数的终止条件为当前分割方案的起始位置等于字符串s的长度。
  4. 递归函数的逻辑为:
    1. 从当前分割方案的起始位置开始,遍历字符串s
    2. 判断当前分割方案的一部分(范围是[cur, i])是否为回文串,如果是,则将其加入到当前分割方案中。
    3. 递归调用函数,将当前分割方案的起始位置设置为当前分割方案的一部分的下一个位置(i+1)。
    4. 如果当前分割方案不为空,则将其最后一个元素删除。
  5. 递归函数的返回值为void。

代码

package main

var (
	ret  [][]string
	path []string
)

func partition(s string) [][]string {
	ret = make([][]string, 0)
	path = make([]string, 0)
	dfs(0, s)
	return ret
}

func isPalindrome(s string) bool {
	for i, sz := 0, len(s); i < sz/2; i++ {
		if s[i] != s[sz-i-1] {
			return false
		}
	}
	return true
}

func dfs(cur int, s string) {
	if cur == len(s) {
		subset := make([]string, len(path))
		copy(subset, path)
		ret = append(ret, subset)
		return
	}
	for i := cur; i < len(s); i++ {
		substr := s[cur : i+1]
		if isPalindrome(substr) {
			path = append(path, substr)
		} else {
			continue
		}

		dfs(i+1, s)

		if len(path) > 0 {
			path = path[:len(path)-1]
		}
	}
}

LeetCode 33. Search in Rotated Sorted Array

题目描述

There is an integer array nums sorted in ascending order (with distinct values).

Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2].

Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums.

You must write an algorithm with O(log n) runtime complexity.

Example 1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

Example 3:

Input: nums = [1], target = 0
Output: -1

思路

这道题目是二分查找的变种,因为数组是有序的,所以可以使用二分查找,但是这道题目的数组是旋转过的,所以需要先找到原数组的起始位置,然后再进行二分查找。

原数组的起始位置可以通过二分查找的方式找到, 原数组的起始位置就是数组中最小的元素的位置。

以数组[4,5,6,7,0,1,2]为例,原数组的起始位置就是0的位置, 而0也是数组中最小的元素。

那么如何找到起始的位置呢?

可以通过二分查找找到数组中间的元素,如果中间元素大于数组的最后一个元素,那么说明原数组的起始位置在中间元素的右边,如果中间元素小于数组的最后元素,那么说明原数组的起始位置在中间元素的左边或者就是中间元素。

以数组[4,5,6,7,0,1,2]为例,中间元素是7,7大于数组的最后一个元素2,所以原数组的起始位置在7的右边,也就是0的位置。

再以数组[6,7,0,1,2,4,5]为例,中间元素是0,0小于数组的最后一个元素5,所以原数组的起始位置在0的左边或者就是0。这里就是0。

如何找到目标元素的位置呢?

我们需要先将原数组扩展, 比如数组[4,5,6,7,0,1,2]扩展为[4,5,6,7,0,1,2,4,5,6,7],其实就是把原数组的起始位置之前的元素复制到数组的后面。

在扩展之后的数组里使用二分查找, 必须将原数组的下标转换为原数组的下标,因为旋转后的数组不是递增的。

假设数组元素个数为n, 数组的起始位置为rot, 数组的最后一位为high, 数组的第一位为low, 那么旋转后的数组的中间元素位置是mid = (low + high) / 2, 真正的中间元素位置是realMid = (mid + rot) % n

可以这样理解, 在[4,5,6,7,0,1,2,4,5,6,7]里, realMid = (rot + (hi + rot) / 2) % n, 也就是 (rot + hi/2) % n, 实际上是(rot + mid) % n

代码

class Solution {
    public int search(int[] nums, int target) {
        int n = nums.length;
        if (n == 0) {
            return -1;
        }
        if (n == 1) {
            return nums[0] == target ? 0 : -1;
        }
        int low = 0;
        int high = n - 1;
        while (low < high) {
            int mid = (low + high) / 2;
            if (nums[mid] > nums[high]) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        int rot = low;
        low = 0;
        high = n - 1;
        while (low <= high) {
            int mid = (low + high) / 2;
            int realMid = (mid + rot) % n;
            if (nums[realMid] == target) {
                return realMid;
            }
            if (nums[realMid] < target) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return -1;
    }
}