训练思维,提高编程能力,不为刷题而刷题
文章目录
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
Swift版本
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var map = [Int : Int]()
for (i, e) in nums.enumerated() {
if let u = map[target - e] {
return [u, i]
}else {
map.updateValue(i, forKey: e)
}
}
return []
}
}
OC版本
- (NSArray *)twoSum:(NSArray <NSNumber *>*)nums target:(NSInteger)target {
NSMutableDictionary *mutDic = [NSMutableDictionary dictionary];
__block NSArray *result = nil;
[nums enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSNumber *num = mutDic[@(target - obj.integerValue)];
if (num) {
result = @[num, @(idx)];
*stop = YES;
}else {
mutDic[obj] = @(idx);
}
}];
return result;
}
测试代码:
NSArray *testArr = [NSArray arrayWithObjects:@(2),@(7),@(11), @(15), nil];
NSArray *resu = [self twoSum:testArr target:18];
if (resu) {
NSLog(@"找到结果:%ld, %ld", [resu[0] integerValue], [resu[1] integerValue]);
}
2. 两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
Swift实现
class Solution {
func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
var listNode1 = l1;
var listNode2 = l2;
//进位
var carry: Int = 0;
let result: ListNode = ListNode(0)
var currentNode = result
while listNode1 != nil || listNode2 != nil || carry > 0 {
let sum: Int = (listNode1?.val ?? 0) + (listNode2?.val ?? 0) + carry
currentNode.next = ListNode(sum % 10)
currentNode = currentNode.next!
listNode1 = listNode1?.next
listNode2 = listNode2?.next
carry = sum / 10
}
return result.next
}
}
OC实现
- (ListNode *)addTwoNumber:(ListNode *)l1 listNode2:(ListNode *)l2 {
ListNode *result = [[ListNode alloc] initWithVal:0];
ListNode *currentNode = result;
ListNode *listNode1 = l1;
ListNode *listNode2 = l2;
//进位标记
NSInteger carry = 0;
while (listNode1 || listNode2 || carry > 0) {
NSInteger sum = listNode1.val + listNode2.val + carry;
currentNode.next = [[ListNode alloc] initWithVal:sum%10];
currentNode = currentNode.next;
listNode1 = listNode1.next;
listNode2 = listNode2.next;
carry = sum / 10;
}
return result.next;
}
3.无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
Swift
/*
* 滑动窗口法
*/
func lengthOfLongestSubstring(_ s: String) -> Int {
let strlen = s.count
let chs: [Character] = Array(s)
var map = [Character : Int]()
var start = 0
var maxLen: Int = 0
for i in 0..<chs.count {
let char = chs[i]
if let preIdx = map[char] {
start = max(start, preIdx+1)
}
map[char] = i;
maxLen = max(maxLen, i-start+1)
print(start, maxLen)
}
return maxLen
}
OC
/*
* 滑动窗口法
*/
- (NSInteger)lengthOfLongestSubstring:(NSString *)s {
if (s.length < 2) {
return s.length;
}
NSInteger strLen = s.length;
NSInteger maxLen = 0;
NSInteger start = 0;
NSMutableDictionary *map = [NSMutableDictionary dictionary];
for (NSInteger i=0; i<strLen; i++) {
unichar c = [s characterAtIndex:i];
NSString *charStr = [NSString stringWithCharacters:&c length:1];
NSNumber *idxNum = [map objectForKey:charStr];
if (idxNum) {
start = MAX(start, [idxNum integerValue] + 1);
}
map[charStr] = @(i);
maxLen = MAX(maxLen, i-start+1);
}
return maxLen;
}
4.寻找两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
Swift
class Solution {
func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double {
let totalLen = nums1.count + nums2.count;
if totalLen % 2 == 0 {
let sum = getKthElement(num1: nums1, num2: nums2, kth: (totalLen+1)/2) + getKthElement(num1: nums1, num2: nums2, kth: (totalLen+2)/2)
return Double(sum) / 2.0
}else {
let res = getKthElement(num1: nums1, num2: nums2, kth: (totalLen+1)/2)
return Double(res)
}
}
/* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较
* nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个
* nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个
* 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个
* 这样 pivot 本身最大也只能是第 k-1 小的元素
* 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组
* 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组
* 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数
*/
func getKthElement(num1: [Int], num2:[Int], kth: Int) -> Int {
let m: Int = num1.count
let n: Int = num2.count
var k = kth
var index1: Int = 0, index2: Int = 0
while true {
//处理边界情况
if index1 == m {
return num2[index2 + k - 1]
}
if index2 == n {
return num1[index1 + k - 1]
}
if k == 1 {
return min(num1[index1], num2[index2])
}
//处理正常情况
let newIdx1: Int = min(index1 + k/2 - 1, m-1)
let newIdx2: Int = min(index2 + k/2 - 1, n-1)
let pivot1 = num1[newIdx1]
let pivot2 = num2[newIdx2]
if pivot1 <= pivot2 {
k -= newIdx1 - index1 + 1
index1 = newIdx1 + 1
}else {
k -= newIdx2 - index2 + 1
index2 = newIdx2 + 1
}
}
}
}
OC
- (CGFloat)findMedianSortedArraysWithNums1:(NSArray *)num1 nums2: (NSArray *)num2 {
NSInteger totalLength = num1.count + num2.count;
if (totalLength % 2 != 0) {
return [self getKthElement:num1 arr2:num2 kth:(totalLength+1)/2];
}else {
CGFloat result = ([self getKthElement:num1 arr2:num2 kth:(totalLength+1)/2] + [self getKthElement:num1 arr2:num2 kth:(totalLength+2)/2])/2.0;
return result;
}
}
/* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较
* 这里的 "/" 表示整除
* nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个
* nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个
* 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个
* 这样 pivot 本身最大也只能是第 k-1 小的元素
* 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组
* 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组
* 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数
*/
- (NSInteger)getKthElement:(NSArray <NSNumber *>*)num1 arr2:(NSArray <NSNumber *>*)num2 kth:(NSInteger)k {
NSInteger m = num1.count;
NSInteger n = num2.count;
NSInteger index1 = 0, index2 = 0;
while (true) {
//处理边界情况
if (index1 == m) {
NSNumber *num = num2[index2 + k - 1];
return [num integerValue];
}
if (index2 == n) {
NSNumber *num = num1[index1 + k - 1];
return [num integerValue];
}
if (k == 1) {
return MIN([num1[index1] integerValue], [num2[index2] integerValue]);
}
//正常情况
NSInteger newIndex1 = MIN(index1+k/2-1, m-1);
NSInteger newIndex2 = MIN(index2+k/2-1, n-1);
NSInteger pivot1 = [num1[newIndex1] integerValue];
NSInteger pivot2 = [num2[newIndex2] integerValue];
if (pivot1 <= pivot2) {
k -= newIndex1 - index1 + 1;
index1 = newIndex1 + 1;
}else {
k -= newIndex2 - index2 + 1;
index2 = newIndex2 + 1;
}
}
}
5.最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
Swift
动态规划
class Solution {
func longestPalindrome(_ s: String) -> String {
let len: Int = s.count
if len < 2 {
return s
}
var begin: Int = 0
var maxLen: Int = 1
let charArr:[Character] = Array(s);
var dp: [[Bool]] = [[Bool]](repeating: [Bool](repeating: false, count: len), count: len)
for i in 0..<len {
dp[i][i] = true
}
for L in 2...len {
for i in 0...len {
let j = L + i - 1
if j >= len {
break
}
if charArr[i] != charArr[j] {
dp[i][j] = false
}else {
if j - i < 3 {
dp[i][j] = true
}else {
dp[i][j] = dp[i+1][j-1]
}
}
if dp[i][j] && j-i+1 > maxLen {
maxLen = j-i+1;
begin = i;
}
}
}
let range = s.index(s.startIndex, offsetBy: begin)..<s.index(s.startIndex, offsetBy: begin+maxLen)
return String(s[range])
}
}
OC
动态规划
- (NSString *)longestPalindrome:(NSString *)s {
NSInteger len = s.length;
if (len < 2) {
return s;
}
NSInteger maxLen = 1;
NSInteger begin = 0;
//将字符串转成字符数组
NSMutableArray *charArr = [NSMutableArray array];
for (NSInteger i=0; i<s.length; i++) {
unichar character = [s characterAtIndex:i];
[charArr addObject:[NSString stringWithFormat:@"%c", character]];
}
NSMutableArray *dp = [NSMutableArray arrayWithCapacity:len];
for (NSInteger i=0; i<len; i++) {
NSMutableArray *innerArr = [NSMutableArray arrayWithCapacity:len];
for (NSInteger j=0; j<len; j++) {
innerArr[j] = [NSNumber numberWithBool:NO];
}
dp[i] = innerArr;
}
for (NSInteger i=0; i<len; i++) {
dp[i][i] = [NSNumber numberWithBool:YES];
}
for (NSInteger L = 2; L<=len; L++) {
for (NSInteger i=0; i<len; i++) {
//确定j的位置,根据j-i+1=L等式
NSInteger j = L+i-1;
// 如果右边界越界,就可以退出当前循环
if (j>=len) {
break;
}
if (![charArr[i] isEqualToString:charArr[j]]) {
dp[i][j] = [NSNumber numberWithBool:NO];
}else {
if (j-i<3) {
dp[i][j] = [NSNumber numberWithBool:YES];
}else {
dp[i][j] = dp[i+1][j-1];
}
}
if ([dp[i][j] boolValue] && j-i+1>maxLen) {
maxLen = j-i+1;
begin = i;
}
}
}
return [s substringWithRange:NSMakeRange(begin, maxLen)];
}
6.N 字形变换
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
Swift
利用二维矩阵模拟
//方法一 利用二维矩阵模拟
func convert(_ s: String, _ numRows: Int) -> String {
//处理边界情况,若1 row or 1 column
let n: Int = s.count
if numRows == 1 || n <= numRows {
return s
}
let t: Int = 2*numRows-2 //一个周期字符数
let cpt: Int = numRows - 1 //一个周期所占列数
let c: Int = (n+t-1)/t * cpt //总列数,注意最后一列填充满
//构造 numrow行c列矩阵
var datas: [[String]] = [[String]](repeating: [String](repeating: "", count: c), count: numRows);
var x: Int = 0
var y: Int = 0
//遍历
for i in 0..<n {
let s: String = String(s[s.index(s.startIndex, offsetBy: i)])
datas[x][y] = s
if i % t < numRows - 1 {//向下遍历
x += 1
}else {//向斜上遍历
x -= 1
y += 1
}
}
var result: String = ""
for i in 0..<numRows {
for j in 0..<c {
let temps = datas[i][j]
if temps.count > 0 {
result = result.appending(temps)
}
}
}
return result
}
压缩矩阵
func convert(_ s: String, _ numRows: Int) -> String {
//处理边界情况,若1 row or 1 column
let n: Int = s.count
if numRows == 1 || n <= numRows {
return s
}
let t: Int = 2*numRows-2 //一个周期字符数
//构造字符串数组
var datas:[String] = [String](repeating: "", count: numRows);
var x: Int = 0
//遍历并填充值
for i in 0..<n {
let s: String = String(s[s.index(s.startIndex, offsetBy: i)])
datas[x] = datas[x].appending(s)
if i % t < numRows - 1 {//向下遍历
x += 1
}else {//向斜上遍历
x -= 1
}
}
var result: String = ""
for i in 0..<numRows {
result = result.appending(datas[i])
}
return result
}
直接构造法
func convert(_ s: String, _ numRows: Int) -> String {
//处理边界情况,若1 row or 1 column
let n: Int = s.count
if numRows == 1 || n <= numRows {
return s
}
let t: Int = 2*numRows-2 //一个周期字符数
var ans: String = ""
for i in 0..<numRows {
var j = 0
while j + i < n {
ans = ans.appending(String(s[s.index(s.startIndex, offsetBy: j+i)]))//第一个字符
if i > 0 && i < numRows - 1 && j + t - i < n {
ans = ans.appending(String(s[s.index(s.startIndex, offsetBy: j+t-i)]))// 当前周期的第二个字符
}
j += t
}
}
return ans
}
K神flag解法(***** 推荐)
func convert(_ s: String, _ numRows: Int) -> String {
if numRows < 2 {
return s
}
var rows = Array(repeating: "", count: numRows)
var i = 0, flag = -1
for c in s {
rows[i].append(c)
if i == 0 || i == numRows - 1 {
flag = -flag
}
i += flag
}
var res = ""
for row in rows {
res += row
}
return res
}
OC
利用二维矩阵模拟
- (NSString *)convert:(NSString *)s numRows:(NSInteger)numRows {
if (!s) {
return nil;
}
NSInteger len = s.length;
//处理边界情况,若1 row or 1 column
if (numRows == 1 || len <= numRows) {
return s;
}
NSInteger t = 2*numRows - 2;//周期
NSInteger np = numRows - 1;//1个周期占用的矩阵列数
NSInteger c = ceil(len+t-1/t) * np;//总列数
//构造r行c列的矩阵
NSMutableArray <NSMutableArray *>*rows = [NSMutableArray arrayWithCapacity:numRows];
for (NSInteger i=0; i<numRows; i++) {
NSMutableArray <NSString *>*tempArr = [NSMutableArray arrayWithCapacity:c];
for (NSInteger j=0; j<c; j++) {
tempArr[j] = @"";
}
rows[i] = tempArr;
}
NSInteger x = 0;
NSInteger y = 0;
//遍历字符串
for (NSInteger i=0; i<len; i++) {
unichar unichar = [s characterAtIndex:i];
NSString *res = [[NSString alloc] initWithCharacters:&unichar length:1];
rows[x][y] = res;
if (i % t < numRows-1) {//向下填充
++x;
}else {//向斜上填充
--x;
++y;
}
}
NSString *result = @"";
for (NSInteger i=0; i<numRows; i++) {
for (NSInteger j=0; j<c; j++) {
NSString *val = rows[i][j];
if (val.length > 0) {
result = [result stringByAppendingString:val];
}
}
}
return result;
}
flag解法
//K神flag解法(*****推荐 )
/*
通过标志位,控制索引在numRows层来回扫描,思路清晰简洁
*/
- (NSString *)convert:(NSString *)s numRows:(NSInteger)numRows {
if (numRows < 2) {
return s;
}
NSInteger len = s.length;
//构造存储字符串的数组
NSMutableArray <NSString *>*datas = [NSMutableArray array];
for (NSInteger i=0; i<numRows; i++) {
datas[i] = @"";
}
NSInteger idx = 0, flag = -1;
for (NSInteger i=0; i<len; i++) {
unichar unichar = [s characterAtIndex:i];
NSString *res = [[NSString alloc] initWithCharacters:&unichar length:1];
datas[idx] = [datas[idx] stringByAppendingString:res];
if (idx == 0 || idx == numRows-1) {
flag = - flag;
}
idx += flag;
}
NSString *result = @"";
for (NSString *str in datas) {
result = [result stringByAppendingString:str];
}
return result;
}
7. 整数反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231,
231 − 1] ,就返回 0。 假设环境不允许存储 64 位整数(有符号或无符号)。
Swift
func reverse(_ x: Int) -> Int {
var x = x;
var n: Int = 0
while x != 0 {
n = n * 10 + x % 10
x /= 10
}
if n < Int32.min || n > Int32.max {
return 0
}else {
return n
}
}
OC
-(int)reverse:(int)x {
int n = 0;
while (x) {
n = n * 10 + x % 10;
x /= 10;
}
if (n > INT32_MAX || n < INT32_MIN) {
return 0;
}else {
return n;
}
}
8. 字符串转换整数 (atoi)
Swift
有限状态机
func myAtoi(_ s: String) -> Int {
let auto = AutomationSwift()
for chara in s {
auto.getChar(chara: chara)
}
return Int(auto.flag) * auto.num
}
enum StateEnum : Int {
case start;
case signed;
case inNumber;
case end;
}
class AutomationSwift: NSObject {
public var flag: Int32 = 1
public var num: Int = 0
var state: StateEnum = .start
let transitionTable:[StateEnum : Array<StateEnum>]
override init() {
self.transitionTable = [
.start: [.start, .signed, .inNumber, .end],
.signed : [.end, .end, .inNumber, .end],
.inNumber: [.end,.end, .inNumber, .end],
.end: [.end, .end, .end, .end,],
];
}
public func getChar(chara: Character) -> Void {
let idx: Int = getCharIdx(chara: chara).rawValue
let newState = self.transitionTable[state]![idx]
self.state = newState
if state == .inNumber {
num = num * 10 + Int(chara.asciiValue! - Character("0").asciiValue!)
num = flag == 1 ? min(num, Int(INT32_MAX)) : min(num, -Int(Int32.min))
}else if state == .signed {
flag = chara == "+" ? 1 : -1
}
}
func getCharIdx(chara: Character) -> StateEnum {
if chara == " " {
return .start
}
if chara == "+" || chara == "-" {
return .signed
}
if chara >= "0" && chara <= "9" {
return .inNumber
}
return .end
}
}
OC
有限状态机
- (int)myAtoi:(NSString *)s {
Automation *autom = [[Automation alloc] init];
for (NSInteger i=0; i<s.length; i++) {
unichar unichar = [s characterAtIndex:i];
[autom getChar:unichar];
}
int res = autom.flagV * autom.num;
return res;
}
@implementation Automation {
NSDictionary <NSNumber *, NSArray *>*_transitionTable;
StateEnum _state;
}
- (instancetype)init {
if (self = [super init]) {
_flagV = 1;
_num = 0;
_state = StateEnumStart;
_transitionTable = @{
@(StateEnumStart) : @[@(StateEnumStart), @(StateEnumSigned), @(StateEnumInNumber), @(StateEnumEnd)],
@(StateEnumSigned) : @[@(StateEnumEnd), @(StateEnumEnd), @(StateEnumInNumber), @(StateEnumEnd)],
@(StateEnumInNumber) : @[@(StateEnumEnd), @(StateEnumEnd), @(StateEnumInNumber), @(StateEnumEnd)],
@(StateEnumEnd) : @[@(StateEnumEnd), @(StateEnumEnd), @(StateEnumEnd), @(StateEnumEnd)],
};
return self;
}
return nil;
}
- (void)getChar:(unichar)character {
NSInteger idx = [self getIndexOfCharacter:character];
NSArray *states = [_transitionTable objectForKey:@((NSInteger)_state)];
_state = (StateEnum)[states[idx] integerValue];
if (_state == StateEnumInNumber) {
_num = _num * 10 + character - '0';
_num = self.flagV == 1 ? MIN(_num, INT32_MAX) : MIN(_num, INT32_MAX);
}else if(_state == StateEnumSigned) {
if (character == '+') {
self.flagV = 1;
}else if(character == '-') {
self.flagV = - 1;
}
}
}
- (NSInteger)getIndexOfCharacter:(unichar)character {
if (character == ' ') {
return 0;
}
if (character == '+' || character == '-') {
return 1;
}
if (character >= '0' && character <= '9') {
return 2;
}
return 3;
}
9. 回文数
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
Swift
func isPalindrome(_ x: Int) -> Bool {
//处理边界情况
//负数or最后一位是0
if x < 0 || (x % 10 == 0 && x/10 != 0) {
return false
}
//如果是回文数,反转后的部分和未翻转的应该相等,因此翻转数字的一半,节省时间及空间
var reverSuffix:Int = 0
//翻转
var x = x
while (x > reverSuffix){
reverSuffix = reverSuffix * 10 + x%10;
x /= 10
}
//当数字为奇数个时,通过reverSuffix/10去除末尾
if x == reverSuffix || x == reverSuffix/10 {
return true
}
return false
}
OC
- (BOOL)isPalindrome:(NSInteger)x {
//处理边界情况
if (x < 0 || (x%10 == 0 && x/10 != 0)) {
return NO;
}
//翻转一半后判断是否相等即可确定是否为回文数
NSInteger reversedNum = 0;
while (x > reversedNum) {
reversedNum = reversedNum * 10 + x%10;
x /= 10;
}
//奇数时多一位,因此除以10
if (x == reversedNum || x == reversedNum/10) {
return YES;
}
return NO;
}
10. 正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
'’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
Swift
动态规划
func isMatch(_ s: String, _ p: String) -> Bool {
let m = s.count
let n = p.count
let matches = { (i:Int, j:Int) ->Bool in
if i == 0 {
return false
}
if p[p.index(p.startIndex, offsetBy: j-1)] == "." {
return true
}
return s[s.index(s.startIndex, offsetBy: i-1)] == p[p.index(p.startIndex, offsetBy: j-1)]
}
var f:[[Int]] = [[Int]](repeating: [Int](repeating: 0, count: n+1), count: m+1)
f[0][0] = 1
for i in 0...m {
for j in 1...n {
if p[p.index(p.startIndex, offsetBy: j-1)] == "*" {
f[i][j] |= f[i][j-2]
if matches(i, j-1) {
f[i][j] |= f[i-1][j]
}
}else {
if matches(i, j) {
f[i][j] |= f[i-1][j-1]
}
}
}
}
return (f[m][n] != 0)
}
OC
动态规划
- (BOOL)matchStr:(NSString *)s pStr:(NSString *)p {
NSInteger m = s.length;
NSInteger n = p.length;
BOOL (^matches)(NSInteger, NSInteger) = ^BOOL(NSInteger i, NSInteger j) {
if (i == 0) {
return NO;
}
if ([p characterAtIndex:j-1] == '.') {
return YES;
}
return [s characterAtIndex:i-1] == [p characterAtIndex:j-1];
};
//构造状态转移表
NSMutableArray *f = [[NSMutableArray alloc] initWithCapacity:m+1];
for (NSInteger i=0; i<m+1; i++) {
NSMutableArray *subArr = [[NSMutableArray alloc] initWithCapacity:n+1];
for (NSInteger j=0; j<n+1; j++) {
subArr[j] = @(0);
}
f[i] = subArr;
}
f[0][0] = @(1);
for (NSInteger i=0; i<=m; i++) {
for (NSInteger j=1; j<=n; j++) {
if ([p characterAtIndex:j-1] == '*') {
f[i][j] = @([f[i][j] intValue] | [f[i][j-2] intValue]);
if (matches(i, j-1)) {
f[i][j] = @([f[i][j] intValue] | [f[i-1][j] intValue]);
}
}else {
if (matches(i, j)) {
f[i][j] = @([f[i][j] intValue] | [f[i-1][j-1] intValue]);
}
}
}
}
return [f[m][n] boolValue];
return false;
}