718[Medium]:Maximum Length of Repeated Subarray

Part1:问题描述

Given two integer arrays A and B, return the maximum length of an subarray that appears in both arrays.

Example 1:

Input:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
Output: 3
Explanation: 
The repeated subarray with maximum length is [3, 2, 1].

Note:

  1. 1 <= len(A), len(B) <= 1000
  2. 0 <= A[i], B[i] < 100

Part2:解题思路

1.公共子序列和公共子串

公共子序列:在母串中都出现过且出现顺序与母串保持一致的字符组成的序列,不要求连续

公共子串:更严格的公共子序列,公共子串是在母串中连续的公共子序列。

例如:

字符串A:introduce

字符串B:tradition

公共子序列:ito,tro等

公共子串:i,tr等

2.动态规划和分治

分治:每一步都会以一个特定的比例缩减问题的规模,比如第一步将问题A分成A/2,A/2,第二部将每个A/2分为A/4,A/4以此类推。

动态规划:也是将大问题划分为小问题,但是缩减的规模不用以一个特定的倍数,每次只需要是原来的问题变小一点就可以。通常可以先写出动态规划的状态方程,按照方程写代码不要太简单。

3.最长公共子序列和最长公共子串的动态规划的状态方程及解释

(1)求字符串A,B的最长公共子序列(字符串下标从0开始):

dp[i][j]:表示字符串A的前i位字符串和B的前j位字符串中最长公共子序列的长度


(2)求字符串A,B的最长公共子串(字符串下标从0开始):

dp[i][j]:表示字符串A的前i位字符串和B的前j位字符串中最长公共后缀的长度。因为是后缀,所以必然是连续子串且至少最后一个字符要相等

因为这里字符串的下标从0开始,所以需要对0进行处理,如果从1开始的话,就可以直接去掉对0的判断且是直接比较A[i]和B[j],会简单一些。


leetcode的这道题是用的整数数组,原理是一样的,并且下标也是从0开始的。根据自己挂了几次发现这个题其实是想求最长公共子串。下面的代码在leetcode上已测试通过。

遇到的问题:

(1)要考虑清楚i,j与你要拿来判断的某个字符下标的关系

(2)循环的范围

Part3:代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
/*
// 求最长公共子序列 
int findLength(vector<int>& A, vector<int>& B) {
	int a = A.size();
	int b = B.size(); 
	int result = 0;
	int** dp = new int*[a + 1];
	for (int i = 0; i < a+1; i++) {
		dp[i] = new int[b + 1];
	}
	for (int i = 0; i < a+1; i++) {
		for (int j = 0; j < b+1; j++) {
			dp[i][j] = 0;
		}
	}
	// i表示A的前i位子串
	// j表示B的前j位子串 
	// 由于字符串从0开始i,j不是我们要比较的那个字符的下标,要考虑清楚ij与我们要用的下标的关系和循环的范围 
	for (int i = 0; i <= a; i++) {
		for (int j = 0; j <= b; j++) {
			if (i == 0 || j == 0) {
				dp[i][j] = 0;
			} else if (A[i- 1] == B[j - 1]) {
				dp[i][j] = 1 + dp[i - 1][j - 1];
			} else {
				dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
			}
			if (dp[i][j] > result) {
				result = dp[i][j];
			} 
		}
	}
	return result;
}
*/

// 求最长公共子串 
int findLength(vector<int>& A, vector<int>& B) {
	int a = A.size();
	int b = B.size(); 
	int result = 0;
	int** dp = new int*[a + 1];
	for (int i = 0; i < a+1; i++) {
		dp[i] = new int[b + 1];
	}
	for (int i = 0; i < a+1; i++) {
		for (int j = 0; j < b+1; j++) {
			dp[i][j] = 0;
		}
	}
	// i表示A的前i位子串
	// j表示B的前j位子串 
	// 由于字符串从0开始i,j不是我们要比较的那个字符的下标,要考虑清楚ij与我们要用的下标的关系和循环的范围 
	for (int i = 0; i <= a; i++) {
		for (int j = 0; j <= b; j++) {
			if (i == 0 || j == 0) {
				dp[i][j] = 0;
			} else if (A[i - 1] == B[j - 1]) {
				dp[i][j] = 1 + dp[i - 1][j - 1];
			} else {
				dp[i][j] = 0;
			}
			if (dp[i][j] > result) {
				result = dp[i][j];
			} 
		}
	}
	return result;
}

int main() {
	vector<int>A;
	vector<int>B;
	int numA, numB, temp;
	cin >> numA;
	cin >> numB;
	for (int i = 0; i < numA; i++) {
		cin >> temp;
		A.push_back(temp);
	}
	for (int i = 0; i < numB; i++) {
		cin >> temp;
		B.push_back(temp);
	}
	cout << findLength(A, B) << endl;
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值