输入包括字符串s(4 ≤ |s| ≤ 50,|s|表示字符串长度),保证s是一个合法的括号匹配序列。
输出一个正整数,满足条件的t的个数。
(())()
3
package go.jacob.day911;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
/*
* 答案参考@郑耀钧
*
* 我原本的思路是:先找出某个括号字符串的左右合法的全排序字符串
* 然后用动态规划构造找到最大子串方法LCS,最后做统计
* 不过很遗憾,这个方法超时了。所以参考了@郑耀钧 的解法,如下
*
* 根据题意,当且仅当修改距离为 1 时 LCS 最大。
* 很容易证明对于两种基本序列 (()) 和 ()() 都有距离为 1 的合法修改。
* 原本想的是对每个左括号,跟每个右括号替换,判断合法后累计。
* 后来发现会漏掉一些情况,那就暴力得干脆一点,把每个符号插入到任意位置,
* 判合法,去重,累计。
*/
public class Demo2 {
private static Set<String> set = new HashSet<String>();
static int count = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
getSequence(str);
System.out.println(set.size() - 1);
sc.close();
}
private static void getSequence(String str) {
for (int i = 0; i < str.length(); i++) {
StringBuilder sb = new StringBuilder(str);
char c = str.charAt(i);
sb.deleteCharAt(i);
for (int j = 0; j < str.length(); j++) {
sb.insert(j, c);
if (isLegal(sb.toString())) {
set.add(sb.toString());
}
sb.deleteCharAt(j);
}
}
}
private static boolean isLegal(String s) {
int left = s.length() / 2, right = s.length() / 2;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(')
left--;
else
right--;
if (right < left)
return false;
}
return true;
}
}
语言:C++ 运行时间: 4 ms 占用内存:376K 状态:答案正确
思路参考@夭寿啦要没Offer啦
使用hash表记录符合的串,即可不用判重。
本套8道题的C++代码已挂到了我的GitHub(https://github.com/shiqitao/NowCoder-Solutions)
#include <iostream>
#include <string>
#include <map>
using namespace std;
int len;
bool ifLegal(string str);
int main()
{
string s; cin >> s;
len = s.size();
map<string, int> hash;
for (int i = 0; i < len; i++) {
string temp = s.substr(0, i) + s.substr(i + 1, len - i - 1);
for (int j = 0; j < len; j++) {
string t = temp.substr(0, j) + s[i] + temp.substr(j, len - 1 - j);
if (t != s && ifLegal(t)) hash[t] = 0;
}
}
cout << hash.size();
return 0;
}
bool ifLegal(string str)
{
int n = 0;
for (int i = 0; i < len; i++) {
if (str[i] == '(') n++;
else n--;
if (n < 0) return false;
}
return true;
}
}
#include<iostream>
#include<string>
#include<set>
#include<stack>
using namespace std;
string s;
bool judge(string);
int main(){
int i,j;
while(cin>>s){
set<string> k;
for(i=0;i<s.length();i++){
char t=s[i];
string tmp=s;
tmp.erase(tmp.begin()+i);
for(j=0;j<=tmp.length();j++){
string ti=tmp;
ti.insert(ti.begin()+j,t);
k.insert(ti);
}
}
int res=0;
for(set<string>::iterator it=k.begin();it!=k.end();it++)
judge(*it)?res++:res=res;
printf("%d\n",res);
}
}
bool judge(string x){
if(x==s) return false;
stack<char> stk;
for(int i=0;i<x.length();i++)
if(x[i]=='(') stk.push(x[i]);
else{
if(stk.empty()) return false;
if(stk.top()!='(') return false;
stk.pop();
}
return stk.empty()==true;
}
//StringBuilder对于经常改变字符串来说效率最高
//两次循环,第一次遍历选择不同位置的,第二次将其插入到剩余字符串任意位置
//最后添加到set中去重,最后将原来的一次减去
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class 字符串最大子集数 {
public static boolean isok(String str) {
int left=0,right=0;
for(int i=0;i<str.length();i++) {
if(str.charAt(i)=='(') left++;
else right++;
if(right>left) break;
}
if(right!=left) return false;
return true;
}
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String str=in.nextLine();
Set<String> set=new HashSet<>();
StringBuilder temp;
StringBuilder temp1;
for(int i=0;i<str.length();i++) {
temp=new StringBuilder();
temp.append(str.substring(0,i)+str.substring(i+1));
for(int j=0;j<=temp.length();j++) {
temp1=new StringBuilder();
temp1.append(temp.substring(0, j)+String.valueOf(str.charAt(i))+temp.substring(j));
if(isok(temp1.toString())) set.add(temp1.toString());
}
}
System.out.println(set.size()-1);
}
}
var readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', function (line) {
var arr = line, alen = arr.length, res = new Set();
for (var i = alen - 2; i > 0; i--) {
var med = arr.split('');
var tmp = arr[i];
med.splice(i, 1);
for (var j = alen - 2; j >= 0; j--) {
med.splice(j, 0, tmp);
if (valid(med.join('')))
res.add(med.join(''));
med.splice(j, 1);
}
}
if(res.has(arr))
res.delete(arr);
console.log(res.size);
});
function valid(str) {
var res = [], len = str.length;
for (var i = 0; i < len; i++) {
if (str.charAt(i) == '(') {
res.push('(');
} else {
res.pop();
}
}
if (res.length === 0)
return true;
else
return false;
} 思路:将输入字符全排列,将重复字符唯一话处理(Set可以解决)以及与原始字符相同的字符除去后,分别与原始字符求CLS。 保留最大长度的CLS,并计数即可,AC50%。
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) { Scanner sc = new Scanner(System.in);
String t = sc.nextLine();
LinkedList<String> list = permutation(t);
HashSet<String> set = new HashSet<>();
int max = 0;
int count = 0;
Iterator it = list.iterator();
while (it.hasNext()) { String temStr = it.next().toString();
if (!isHe(temStr))
continue;
if (temStr.equals(t))
continue;
set.add(temStr);
}
Iterator it2 = set.iterator();
while(it2.hasNext()){ String temStr2 = it2.next().toString();
int temS = getMaxSubstringLen(t, temStr2);
if (temS > max) { count = 0;
max = temS;
count++;
} else if (temS == max) { count++;
} else
continue;
}
System.out.println(count);
}
// 将字符t全排列
public static LinkedList<String> permutation(String str) { LinkedList<String> linkedString = new LinkedList<String>();
if (str.length() <= 1) { linkedString.add(str);
return linkedString;
}
for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i);
// consider the case in which the characters may be duplicated.
if (i > 0 && ch == str.charAt(i - 1)) { continue;
}
String newStr = remove(str, i);
LinkedList<String> newStrList = permutation(newStr);
for (int j = 0; j < newStrList.size(); j++) { linkedString.add(ch + newStrList.get(j));
}
}
return linkedString;
}
public static String remove(String str, int i) { if (i == 0)
return str.substring(1, str.length());
if (i == str.length() - 1)
return str.substring(0, i);
return str.substring(0, i) + str.substring(i + 1, str.length());
}
// 返回两个字符串的最长公共子序列的长度
public static int getMaxSubstringLen(String x, String y) { int xLen = x.length() + 1;
int yLen = y.length() + 1;
int rLen = xLen > yLen ? xLen : yLen;
int cLen = xLen < yLen ? xLen : yLen;
int[][] c = new int[rLen][cLen];
for (int i = 1; i < rLen; i++) { for (int j = 1; j < cLen; j++) { if (x.charAt(i - 1) == y.charAt(j - 1)) { c[i][j] = c[i - 1][j - 1] + 1;
} else if (c[i - 1][j] >= c[i][j - 1]) { c[i][j] = c[i - 1][j];
} else { c[i][j] = c[i][j - 1];
}
}
}
return c[xLen - 1][yLen - 1];
}
public static boolean isHe(String str) { Stack<Character> stack = new Stack<>();
boolean flag = true;
for (int i = 0; i < str.length(); i++) { if (str.charAt(i) == '(') stack.push(str.charAt(i));
else { if (stack.isEmpty()) { flag = false;
} else { char c = stack.pop();
if (c != '(') flag = false;
}
}
}
return flag;
}
}
#include <stdio.h>
#include <algorithm>
#include <string>
#include <set>
using namespace std;
char str[55];
void read() {
scanf("%s", str);
}
bool test(const string& s) {
int cnt = 0;
for (int i = 0; s[i]; ++i) {
s[i] == '(' ? ++cnt : --cnt;
if (cnt < 0) {
return false;
}
}
return true;
}
void work() {
set<string> record;
for (int i = 1; str[i+1]; ++i) {
string tmp(str);
tmp.erase(i, 1);
for (int j = 1; str[j]; ++j) {
if (str[i] == str[j]) continue;
string s(tmp);
s.insert(j, 1, str[i]);
if (test(s)) {
record.insert(s);
}
}
}
printf("%lu\n", record.size());
}
int main() {
read();
work();
return 0;
} s = list(input())
def is_valid(s):
l, r = 0,0
for i in s:
if i == "(":
l+=1
else:
r+=1
if r>l:
return False
return True
l = len(s)
res = []
for i in range(l):
s_1 = s.copy()
cur_value = s_1.pop(i)
s_new = s_1.copy()
for j in range(l):
if i==j:
continue
s_new.insert(j, cur_value)
if is_valid(s_new) and s_new!=s:
if s_new not in res:
res.append(s_new)
s_new = s_1.copy()
print(len(res)) ## 输入转为字符串
s = list(input())
## 保存 t 序列
s_set = []
## 暴力循环
length = len(s)
# 遍历序列中每个值,采用pop删除,接着用insert插入在不同位置
# 当序列合法时保存
# 合法性判断依据 无论序列多长,序列从左到右,num('(')>=num(')')始终成立
# 初始化计数器count ,当count==lenght,数据合法,进行保存
# 即每次计数中num('(')>=num(')')成立,计数器+1,
# 最后len(t)即可
for i in range(length):
s_1 = s.copy() #初始化序列
value = s_1.pop(i) #
s_new = s_1.copy()
for j in range(length):
s_new.insert(j,value)
###判断合法性
num_left = num_right = 0
count = 0
for p in range(length):
num_left = len([x for x in s_new[:p] if x == '('])
num_right = len([x for x in s_new[:p] if x == ')'])
if num_left >= num_right:
count += 1
if count == length:
if s_new not in s_set:
s_set.append(s_new)
s_new = s_1.copy()
s_result = [s]
for i in s_set:
if i not in s_result:
s_result.append(i)
print (len(s_result)-1)
a = input()
import copy
list1 = []
a_l = len(a)
for i in range(len(a)):
if a[i] == '(':list1.append(0)
else:list1.append(1)
#判断合法化,注意一旦数列输入到这个函数里面的时候,数列将被改变
def legal(list1):
i = -1
tem = 0
while list1 and i <= len(list1)-2:
i += 1
if list1[i] == 0 and list1[i+1] == 1 and len(list1) != 2:
del list1[i]
del list1[i]
i = -1
elif len(list1) == 2 and (list1[i] != 0 or list1[i+1] != 1) :
tem = 0
break
elif len(list1) == 2 and list1[i] == 0 and list1[i+1] == 1 :
tem = 1
break
else:
continue
return tem
#重复性判断函数
list4 = []
def repeat(list3):
if list3 not in list4:
return True
else:
return False
def main():
n = 0
while n == 0:
for j in range(len(list1)):
list2 = copy.deepcopy(list1)
tem = list1[j]
del list2[j]
for i in range(len(list2)+1):
list3 = copy.deepcopy(list2)
list3.insert(i,tem)
list5 = copy.deepcopy(list3)
#print(list4)
if list5 != list1 and repeat(list5) and legal(list5) :
n += 1
list4.append(list3)
else:
continue
list2.insert(j,tem)
print(n)
main()
#最长公共字括号序列最终版
#1.经过一系列pop和insert操作生成s3(元素换位后生成的所有t的列表)
s0 = list(input())
l = len(s0)
#print(l)
k1 = 0
s3 = []
#s0 原始括号序列
#s1 原始括号序列的备份:会被pop掉一个元素
#s2 备份被pop掉一个元素的s1后再在自身的各个位置insert一个元素
#s3 包含所有得到的t
#s4 筛选出不重复的且与原始s0不同的t
for i in range(l): #遍历s0中各元素,把每个元素都拿出来并插入新位置(这里是所有位置都插了,
#因为后面反正会判断重复性),
s1 = s0.copy() #s0的备份:s1的初始化,因为每次拿数据都是从最初的s0上拿,所以拿数据之前的s0要保留
#print(s1)
a = s1.pop(i) #pop数据
s2 = s1.copy() #s1的备份:拿了数据以后要在各个位置插入,所有pop后的s1要保留
#print(a)
for j in range(l):#按照原来s0 的位置信息在各个位置插入刚刚pop出来的a
s2.insert(j,a)
#print(s1)
s3.append(s2) #生成新的t并加入到元素为t的s3中
s2 = s1.copy()#初始化s2
j += 1
#2.去除重复的t及原始s0后得到s4
s4 = []
for i in s3:
if not i in s4: #if not (i in s4 or i == s0): 也可以用并集的互补集表示
if i != s0 : # and i[0] == '(' and i[len(s0)-1] != '('这里判不判断首位是不是‘(’并不重要,
#毕竟后面也有判断按顺序读取s4【m】元素时,左括号数量是否大于右括号数量,一旦第一个是右括号,
#元素s4【m】就不合法了
s4.append(i)
#print(s3,len(s3))
#print(s4,len(s4))
#3.判断s4中t的合法性并计算s4中合法t的个数
for m in range(len(s4)): #遍历s4中的各个t
n0 = 0 #参数初始化
n1 = 0
for n in range(len(s4[m])): #遍历单个t的各个元素时,判断左括号是否多于右括号,一旦左括号少于右括号,
if s4[m][n] == '(': #就是不合格括号序列, k1(作为flag参数)减一,
n0 += 1
else:
n1 += 1
if n0 < n1 :
k1 -= 1
break
k1 += 1 #给s4中的每个t都加1,在遇到不合法序列时减一,
print(k1) #其实这个加1可以省略,直接拿len(s4)来减就好了
import java.util.*;
public class KindsSubSeq {
/*
* 参考解题思路:https://www.nowcoder.com/test/question/done?tid=14539495&qid=126953#summary
* 最长的子序列和原字符串只相差一,暴力替换原字符串任意个字符,然后判断新生成的字符是否是满足括号特性,满足则添加到set集合中(自动去重)
* */
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
set.clear();
String line = scanner.nextLine();
getSequence(line);
// 包含原字符串
System.out.println(set.size() - 1);
}
}
private static void getSequence(String line) {
for (int i = 0; i < line.length(); i++) {
// 每次删除一个字符
StringBuilder stringBuilder = new StringBuilder(line);
char c = line.charAt(i);
stringBuilder.deleteCharAt(i);
for (int j = 0; j < line.length(); j++) {
// 对应位置插入一个字符
stringBuilder.insert(j, c);
if (isValidBracket(stringBuilder.toString())) {
set.add(stringBuilder.toString());
}
// 下次循环判断,删除该字符
stringBuilder.deleteCharAt(j);
}
}
}
// 判断某字符串是否满足括号特性
private static boolean isValidBracket(String str) {
int left = str.length() / 2;
int right = left;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '(') {
left--;
} else {
right--;
}
if (left > right) {
return false;
}
}
return true;
}
private static Set<String> set = new HashSet<>();
}
import java.util.*;
public class Main {
private static HashSet<String> set = new HashSet<String>();
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
/*
* 思路:只挪动一个符号,得到的合法序列就是满足自子序列最大的序列。子序列的长度=|s|-1
* 所以,对每一个半括号,随意插入任意位置,判断是否合法,合法则放到set里
* 最后的数字=size()-1(排除原来的序列)
* */
//小优化:原本的序列是合法序列,则头和尾的符号是确定的,没有必要移动。
for(int i=1;i<s.length()-1;i++){
StringBuilder bd = new StringBuilder(s);
char c = bd.charAt(i);
bd.deleteCharAt(i);
for(int j=1;j<s.length()-1;j++){
bd.insert(j,c);
if(isLeagal(bd)){
set.add(bd.toString());
}
bd.deleteCharAt(j);
}
}
//有一个是原序列
System.out.println(set.size()-1);
sc.close();
}
private static boolean isLeagal(StringBuilder bd){
int count =0;
for(int i=0;i<bd.length();i++){
if(bd.charAt(i) == '('){
count++;
}else{
count--;
}
if(count<0)return false;
}
return true;
}
}
/*参考一楼二楼内容*/import java.util.HashSet;
# coding=utf-8
__author__ = 'xiaofu'
def solution(s):
# 只需要移动一个字符即可,保持其他n - 1个的相对位置不变
# 然后判断这样生成的新字符串是否是合法的括号序列
# 快速去重
target_s = set()
for i, c in enumerate(s):
# 删除第i个位置的字符
s1 = s[0: i] + s[i + 1: ]
# len(s) = len(s1) + 1
# 假设s1为 xyz 用下划线表示可以插入的位置 _x_y_z_
for j in range(len(s1) + 1):
# 将字符c插入到任意一个位置
# [0:0]会生成空串
s2 = s1[0: j] + c + s1[j:]
# 直接由后面使用set来判断是否加入了与s相同的序列
# 效率会更高,不用每次都检查一遍字符串
# if s2 == s:
# # 有可能会产生和s一样的结果
# continue
# 检查括号是否匹配
left_parentheses = 0 # 左括号数量
# 不需要再多一个右括号的变量,否则判断更加麻烦
# right_parentheses = 0 # 右括号数量
for char_in_s2 in s2:
if char_in_s2 == '(':
left_parentheses += 1
else:
left_parentheses -= 1
if left_parentheses < 0:
# 说明出现了左边没多余(,而出现了),导致这个)不可能闭合
break
if left_parentheses == 0:
# s2 is valid
target_s.add(s2)
if s in target_s:
return len(target_s) - 1
return len(target_s)
# def insert_string_before(source, string, position):
# return source[0: position] + string + source[position:]
def main():
s = input().strip()
print(solution(s))
# print(solution("((())())"))
if __name__ == '__main__':
main()
先正向遍历一遍,然后反向遍历一遍,再正向遍历两遍,时间复杂度为O(n)
#include<stdio.h>
#include<stdlib.h>
int main(void){
int left_kuohao = 1;
int right_kuohao = 0;
char before = '(';
char s[51];
int sum = 0;
scanf_s("%s", s,30);
int i;
int alter_left_kuohao = 0;
for (i = 1; s[i]; i++){
if (s[i] == '('){
left_kuohao++;
alter_left_kuohao++;
if (before == ')'){
sum += right_kuohao;
}
}
else{ right_kuohao++;
if (before == '('){
sum += alter_left_kuohao;
}
if (left_kuohao - right_kuohao == 0){
alter_left_kuohao = -1;
}
}
before = s[i];
}
int lenth = i;
left_kuohao = 0;
right_kuohao = 1;
char after = ')';
int alter_right_kuohao = 0;
for (i = i - 2; i > -1; i--){
if (s[i] == ')'){
right_kuohao++;
alter_right_kuohao++;
if (after == '('){
sum += left_kuohao;
}
}
else{
left_kuohao++;
if (after == ')'){
sum += alter_right_kuohao;
}
if (right_kuohao == left_kuohao){
alter_right_kuohao = -1;
}
}
after = s[i];
}
int count = 0;
for (i = 1; i < lenth - 2; i++){
if (s[i] == ')'&&s[i + 1] == '('){
count++;
i++;
}
else if (count){
sum -= count*(count + 1) / 2;
count = 0;
}
}
if (count >0){
sum -= count*(count + 1) / 2;
}
count = 0;
left_kuohao = 1;
right_kuohao = 0;
for (i = 1; i < lenth - 2; i++){
if (s[i] == '('&& s[i + 1] == ')'&& left_kuohao > right_kuohao){
left_kuohao++;
right_kuohao++;
count++;
i++;
}
else{
sum -= count*(count + 1) / 2;
count = 0;
if (s[i] == '('){
left_kuohao++;
}
else{
right_kuohao++;
}
}
}
if (count >0){
sum -= count*(count + 1) / 2;
}
printf("%d", sum);
system("pause");
return 0;
}
#include<iostream>
#include<set>
#include<string>
using namespace std;
bool fun(string s);
int main()
{
string s;
cin >> s;
set<string> slist;
for (auto i = 0; i < s.size(); ++i)
{
string str = s;
char ch = str[i];
str.erase(i, 1);
for (auto j = 0; j < str.size(); ++j)
{
string tem = str;
tem.insert(j, 1, ch);
if (fun(tem)&&tem!=s)
slist.emplace(tem);
}
}
cout << slist.size() << endl;
}
bool fun(string s)
{
string::iterator beg, end;
beg = end = s.begin();
while (1)
{
while (beg != s.end() && *beg != '(')
++beg;
while (end != s.end() && *end != ')')
++end;
if (beg<=end&&beg != s.end() && end != s.end())
{
++beg;
++end;
continue;
}
else if (beg == s.end() && end == s.end())
return true;
else
return false;
}
}