【洛谷】P1032字串变换—Java代码

题目

原题链接

前言

今天上洛谷发现,我终于从蓝名升为绿名了。。开森。。。

回到正题,由于这学期在学java,就想着用java敲。结果被自己秀的头皮发麻,用java最好要了解它源码的底层实现原理,不然很可能会用错的,这种错误就很难找了。在调了两个小时我的java代码后还是不行,我就去恰饭了。晚上我用C/C++把这题又敲了一遍,交上去结果跟之前的java代码一样,在比对了题解区的代码和我的代码,后来才发现在处理字符串的一处细节出错了,不过大体思路还是正确的。心态炸裂。

在调试这个题目时我发现了,这个题目的测试数据不够完善

下面,我将会以解释如何用java写这一题。

分析

这个题目是在洛谷普及训练场的广搜专题,用广搜无疑了。这一点我就不赘述了。除此之外,这题的难点就是在:扩展这颗广搜树时,要进行子串搜索和替换!这个在题解区的实现方法比较多,我来介绍一下我的实现方法。

1、java中的String类的replace()方法和StringBuilder类的略有不同

//从下标fromIndex开始到主串末尾的范围内,搜索子串str。搜到,返回第一次出现的下标;否则返回-1
int indexOf(String str, int fromIndex); 

//我们的需求是:仅仅替换第一次出现的子串。但String类并没有该方法
//String类
String replace(charSequence target, charSequence replacement); //详情查看编译器的提示

//StringBuilder类
//将主串的[start, end)部分替换为str,返回一个新的StringBuilder
StringBuilder replace(int start, int end, String str); 

有了上面第1和第3个方法,就可以非常方便地实现题目所需要的子串搜索的需要(具体见代码)。当然C++的string也有类似的两个方法!

2、StringBuilder类并没有重写equals()方法,换言之HashSet<StringBuilder>是没有意义的

这题去重可以用set的,当然我看到题解区有用map的,没太大的必要,但问题不大也不是重点。

本来我用StringBuilder类的,后来在上网查了一下,并且自己查看源码之后,发现StringBuilder似乎并没有重写equals()方法。了解过set底层源码(这我就不多说了,感兴趣的可以自行百度)的应该知道,装在set里面的类需要重写hashCode()和equals()。故用set装自定义类时要注意重写这两个方法。

3、java中的队列是哪一个类?

队列完全可以用数组去模拟。但要封装一个队列类,用链表还是最有优势的。java集合中的LinkedList类是用链表实现的一种动态数组,里面的方法完全满足队列的需要,可以当队列使用。

4、测试数据不够完善

举个简单的例子:

xababaz(中间的a属于两个"aba")  xabyz 
aba y

容易看出来,有两种替换方式,得到的结果分别是:xybaz和xabyz。假如有这种特殊数据,我觉得题解区有一部分代码过不了。

5、读入优化:使用Scanner类读取数据略慢,可以模仿大神使用IO流自定义输入类

这个我也不多说,学过IO流的同学不妨可以敲一下

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
using namespace std;

typedef struct Node
{
	string str;
	int steps;
	Node() {}
	Node(string s, int a):str(s),steps(a) {}
}Node;

string l[25]; //可能出现abc->123 abc->456的情况,不能使用map<string,string> 
string r[25];
int n;

string src; //源串 
string dest; //目标串 

set<string> st; //装已经搜过的字符串 

/*
xababaz  xabyz
aba y
*/ 
void bfs()
{
	queue<Node> q;
	q.push(Node(src, 0));
	
	int ans=0;
	
	while(!q.empty())
	{
		Node head=q.front();
		q.pop();
		
		
		if(st.count(head.str)) //已经搜过 
			continue;
		
		if(head.steps>10) //ans=0
			break;
			
		if(head.str==dest) //若src==dest,ans=0 
		{
			ans=head.steps;
			break;
		}
		
		st.insert(head.str);
		for(int i=0;i<n;i++) //枚举所有规则 
		{	
			int index=0;
			while((index=head.str.find(l[i], index))!=string::npos)//对于某一条规则,可能不止一个地方可以替换 
			{
				string tmp=head.str; //创一个副本 
				string s=tmp.replace(index, l[i].length(), r[i]);
				//index+=l[i].length(); //如果用的这一行代码,可以AC。但对于上面的特例输出:NO ANSWER!
				index++; //用这一行代码,对于上面的特例输出:1。但是上面那行代码快几十ms
				q.push(Node(s, head.steps+1));
			}
		}	
	}
	
	if(ans==0)
		cout<<"NO ANSWER!"<<endl;
	else
		cout<<ans<<endl;
}

int main()
{
	cin>>src>>dest;
	while(cin>>l[n]>>r[n])
		n++;
	
	bfs();
	return 0;
}

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.StringTokenizer;


public class Main
{
	static String src; //源串A
	static String dest; //目标串B
	static String[][] rule=new String[25][2];
	static int n=0; //共有多少条规则
	static class Node
	{
		String str;
		int steps;
		
		public Node() {}
		public Node(String str, int steps) 
		{
			this.str = str;
			this.steps = steps;
		}
	}
	static class MyScanner
	{
		BufferedReader reader; //字符缓冲流
		StringTokenizer tokenizer; //用于分隔字符串
		
		public MyScanner(InputStream is)
		{
			reader=new BufferedReader(new InputStreamReader(is), 32768); //字节流(System.in)->字符流->字符缓冲流
			tokenizer=null;
		}
		
		public String next() 
		{
			while(tokenizer==null || !tokenizer.hasMoreTokens())
			{
				try {
					tokenizer=new StringTokenizer(reader.readLine()); //用字符串缓冲流读取一行,然后分隔
				} catch (IOException e) {
					e.printStackTrace();
				} 
			}
			return tokenizer.nextToken(); 
		}
		public boolean ready() throws IOException
		{
			return reader.ready();
		}
	}
	
	public static void bfs()
	{
		HashSet<String> used=new HashSet<>(); //装搜过的字符串。要求重写过hashCode()和equals()方法
		LinkedList<Node> queue=new LinkedList<>();
		queue.add(new Node(src, 0));
		int ans=0;
		
		while(!queue.isEmpty())
		{
			Node head=queue.removeFirst();
			
			if(used.contains(head.str))
				continue;
			
			if(head.steps>10) //ans=0
				break; 
			
			if(head.str.equals(dest)) //若A==B,也属于无解。正好也符合ans=0
			{
				ans=head.steps;
				break;
			}
			
			used.add(head.str);
			for(int k=0;k<n;k++) //枚举规则
			{
				int index=0;
				while((index=head.str.indexOf(rule[k][0], index))!=-1)
				{
					StringBuilder s=new StringBuilder(head.str).replace(index, index+rule[k][0].length(), rule[k][1]); 
					queue.add(new Node(s.toString(), head.steps+1));
					index+=rule[k][0].length();
				}
			}
		}
		if(ans==0)
			System.out.println("NO ANSWER!");
		else
			System.out.println(ans);
		
	}
	
	public static void main(String[] args) throws IOException 
	{
		
		MyScanner msc=new MyScanner(System.in);
		src=msc.next();
		dest=msc.next();
		while(msc.ready()) 
		{
			rule[n][0]=msc.next();
			rule[n][1]=msc.next();
			n++;
		}
		/*
		Scanner sc=new Scanner(System.in);
		src=sc.next();
		dest=sc.next();
		while(sc.hasNext())
		{
			rule[n][0]=sc.next();
			rule[n][1]=sc.next();
			n++;
		}
		*/
	
		bfs();
	}
	
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章