7月算法训练------第五天(双指针)解题报告
题目类型:双指针
题目难度:简单
第一题、392. 判断子序列
-
题目链接:392. 判断子序列
-
思路分析:
我们先将字符串s
转为字符数组chs
,定义一个index
变量,表示从字符串t的第index
位找chs
中的字符;
然后遍历字符串t
,在t
中找chs[i]
,找到chs[i]
,就更新index
的值;
如果没找到,就返回false
;
每次循环完,使index++
,表示下一次从index+1
位开始找chs[i]
;
如果都能找到,则返回true。 -
需要用到
java.lang.String
类中的indexOf()
方法:
返回值 | 方法名 | 方法作用 |
---|---|---|
int | indexOf(String str, int fromIndex) | 返回此字符串的指定子字符串中第一个出现在索引中,从指定索引处开始。 |
代码:
class Solution {
public boolean isSubsequence(String s, String t) {
char[] chs = s.toCharArray();
// char[] cht = t.toCharArray();
int index = 0;
for(int i = 0; i < chs.length; i++){
index = t.indexOf(chs[i], index);
if(index == -1){
return false;
}
index++;
}
return true;
}
}
第二题、
- 题目链接:541. 反转字符串 II
- 思路分析:
- 以题目中的例子:
"abcdefg"
和2
- 我们分析发现,这一题就是让这个字符串的某一部分反转,而这个子串满足它是这个字符串的每
2k
个序列的前k
个,我们可以用每k个字符串划分为一组子串的形式: - 要划分的字符串:
0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
a | b | c | d | e | f | g |
- 先将这个字符串按每
k
(这里k=2
)位为一组划分,这里要注意如何精确地计算出要申请的字符串数组strCh
的长度是多少:
strCh[0] | strCh[1] | strCh[2] | strCh[3] |
---|---|---|---|
ab | cd | ef | g |
- 然后我们找出要反转的子串,这里我们需要注意怎样找到数组中的要反转的那一组:
strCh[0] | strCh[1] | strCh[2] | strCh[3] |
---|---|---|---|
ba | cd | fe | g |
红色标注就是我们要反转的字符串。
- 需要用到的知识:
java.lang.String
类中截取子字符串的方法substring(int beginIndex, int endIndex)
:
返回类型 | 方法名 | 方法功能 |
---|---|---|
String | substring(int beginIndex, int endIndex) | 返回一个字符串,这个字符串的子串。 |
String | substring(int beginIndex) | 返回一个字符串,这个字符串的子串。 |
java.lang.StringBuilder
中反转字符串的方法reverse()
:
- 代码:
class Solution {
public String reverseStr(String s, int k) {
String[] strCh; //srtCh的长度由s的长度与k决定
int mark = 0; //用来辅助计算循环次数
if(s.length() % k == 0){
strCh = new String[s.length() / k];
mark = s.length() / k;
}else{
strCh = new String[s.length() / k + 1];
mark = s.length() / k + 1;
}
for(int i = k; i <= k * mark; i += k){
if(i < s.length()){
StringBuilder sb = new StringBuilder(s.substring(i-k, i));
if((i / k) % 2 == 1){
sb.reverse();
}
strCh[i / k - 1] = sb.toString();
}else{
StringBuilder sb = new StringBuilder(s.substring(i-k, s.length()));
if((i / k) % 2 == 1){
sb.reverse();
}
strCh[i / k - 1] = sb.toString();
}
}
StringBuilder sb2 = new StringBuilder();
for(int i = 0; i < strCh.length; i++){
sb2.append(strCh[i]);
}
return sb2.toString();
}
}
第三题、面试题 16.24. 数对和
- 题目链接:面试题 16.24. 数对和
- 思路分析:
- 看到这一题,我们要向用双指针做,首先要对数组排序;
这一题比较简单,要求的是每组是两个数: - 我们先定义一个左指针
l=0
和右指针r=nums.length
;- 当
nums[l] + nums[r] == target
时,我们将nums[l]
和nums[r]
都放入定义好的ArrayList lint
中,然后将l++
(l
向右移)和r--
(r
向左移); - 当
nums[l] + nums[r] > target
时,说明此时需要将两数之和变小,而只有r
向右移时,两数之和在变小,所以只将r--
; - 当
nums[l] + nums[r] < target
时,说明此时需要将两数之和变大,而只有l
向左移时,两数之和在变大,所以只将l++
;
- 当
- 代码:
class Solution {
public List<List<Integer>> pairSums(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> llist = new ArrayList();
int l = 0, r = nums.length - 1;
while(r > l){
List<Integer> lint = new ArrayList();
if(nums[l] + nums[r] == target){
lint.add(nums[l]);
lint.add(nums[r]);
llist.add(lint);
l++;
r--;
}else if(nums[l] + nums[r] > target){
r--;
}else{
l++;
}
}
return llist;
}
}
第四题、696. 计数二进制子串
题目链接:696. 计数二进制子串
思路分析:
- 暴力解法:
时间复杂度O(N^2)
;
我们用一个数来表示当前的得分score
,当我们遇见0
时,得分减一,当我们遇见1
时,得分加一;
当得分等于0
时,我们就将结果num
加一;
为了控制0
或1
是连续的,当我们遍历的当前循环第一位是0
&&
第j-1
位是1
&&
第j
位是0
;
当我们遍历的当前循环第一位是1
&&
第j-1
位是0
&&
第j
位是1
时,这两种情况都是不连续的情况,所以直接舍弃;
为了保证上面的情况成立,得分score
的初值也由当前循环第一位决定;
当前循环第一位是0
时,score=-1
;
当前循环第一位是1
时,score=0
;
但这种方法时间复杂度过高,不能通过;
暴力代码:
class Solution {
public int countBinarySubstrings(String s) {
char[] ch = s.toCharArray();
int score = 0, num = 0;
for(int i = 0; i < s.length(); i++){
if(ch[i] == '0'){
score = -1;
}else{
score = 1;
}
for(int j = i+1; j < s.length(); j++){
if(ch[i] == '0' && ch[j - 1] == '1' && ch[j] == '0'){
break;
}
if(ch[i] == '1' && ch[j - 1] == '0' && ch[j] == '1'){
break;
}
if(ch[j] == '0'){
score-=1;
}else{
score+=1;
}
if(score == 0){
num++;
break;
}
}
}
return num;
}
}
只能另想一种时间复杂度低的方法:看了答案很受启发,答案确实牛批:
比如我们输入字符串为:“11011100”;
我们先让它变成一个数组,数组变换方法是:
拿例子说:现有2个"1",将2入alist;
然后有1个"0",将1入alist;
然后有3个"1",将3入alist;
然后有2个"0",将2入alist。
最后的数组就是:{2,1,3,2};
每两个相邻的数求最小值,累加就是答案了:
{2,1}的最小值是1,加1;
{1,3}的最小值是1,加1;
{3,2}的最小值是2,加2。
最终值为4。
代码:
class Solution {
public int countBinarySubstrings(String s) {
List<Integer> alist = new ArrayList();
int ptr = 0, n = s.length();
while(ptr < n){
char c = s.charAt(ptr);
int count = 0;
while(ptr < n && s.charAt(ptr) == c){
count++;
ptr++;
}
alist.add(count);
}
int ans = 0;
for(int i = 1; i < alist.size(); i++){
ans += Math.min(alist.get(i), alist.get(i-1));
}
return ans;
}
}