【洛谷】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();
	}
	
}

 

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