【问题描述】
我从家里(Home)出发,沿着公路骑行。在每一个路口使用投掷硬币的方式来决定方向,正面意味着向左转,背面向右转。如果遇到三个方向(十字路口)可选,那么就投掷硬币两次,两次正面是左转,一正一反是直行,一反一正是右转,两次皆反则再投掷2次来决定。整个过程持续到我能回到家中(Home),下面有一副公路的地图,图中每个选择的路口都用一个字母予以标识。

题目中会给定一个硬币正反的序列——该序列循环使用,即使用到该序列的最后一个字母后,下一个就是该序列的第一个字母,H代表正面,T代表背面。现在需要计算回到Home的时候我已经投掷了几次硬币。如果永远回不到Home那么就返回-1。
定义:
类 RandomRide
方法 public int flipCount(String flips)
约束:
1、flips中包含1至50个字母;
2、字母序列仅由'H' 或 'T'组成。
测试用例:
1、"H" Returns: 10
2、"HHTTTTTHTHTHHHTT" Returns: 11
3、"HTH" Returns: 13
4、"HHHTHHHHHHTTTHHHHHHHHHTTHHT" Returns: 328
【算法思想】
我觉得本题只要解决两个基本问题后就比较简单了,一个是如何建模来方便的处理转向的问题,另一个就是如何判断当前的走法是一种死循环(永远到不了Home)。
1、第一个问题比较麻烦的地方是,左右是与行驶的方向相关的,为了避免每次都考虑行驶的方向,程序中建立的一个map存储了所有节点的方向信息,例如对于节点B,存储的是"AGCAG",顺序是“后、上、前、下、后、上、前”如果像B一样没有前向节点那么就是“后、上、下、后、上”,Home节点以"#"代表。
2、第二个问题,程序中维护一个map,如果当前节点的“形式”存在于该map中,那么就认为是重复。这种“形式”为,前一个节点+当前节点+方向+选择的硬币在整个序列中的位置。
我从家里(Home)出发,沿着公路骑行。在每一个路口使用投掷硬币的方式来决定方向,正面意味着向左转,背面向右转。如果遇到三个方向(十字路口)可选,那么就投掷硬币两次,两次正面是左转,一正一反是直行,一反一正是右转,两次皆反则再投掷2次来决定。整个过程持续到我能回到家中(Home),下面有一副公路的地图,图中每个选择的路口都用一个字母予以标识。

题目中会给定一个硬币正反的序列——该序列循环使用,即使用到该序列的最后一个字母后,下一个就是该序列的第一个字母,H代表正面,T代表背面。现在需要计算回到Home的时候我已经投掷了几次硬币。如果永远回不到Home那么就返回-1。
定义:
类 RandomRide
方法 public int flipCount(String flips)
约束:
1、flips中包含1至50个字母;
2、字母序列仅由'H' 或 'T'组成。
测试用例:
1、"H" Returns: 10
2、"HHTTTTTHTHTHHHTT" Returns: 11
3、"HTH" Returns: 13
4、"HHHTHHHHHHTTTHHHHHHHHHTTHHT" Returns: 328
- package topcoder.t_1;
- import java.util.HashMap;
- import java.util.Map;
- public class RandomRide {
- private Map<String, String> map = null;
- private Map<String, String> repeat = new HashMap<String, String>();
- private int count = 0;
- public int flipCount(String flips) {
- String directStr = flips + flips;
- initMap();
- String start = "#";
- String end = "A";
- String tmp = "";
- while (!"#".equals(end)) {
- tmp = start;
- start = end;
- end = getNextPoint(end, tmp, directStr);
- if ("".equals(end))
- return -1;
- System.out.println(start + "(" + this.count + ") ");
- }
- return this.count;
- }
- // 1-left 2-mid 3-right || 1-left 2-right
- private String getNextPoint(String nowPoint, String prePoint, String directStr) {
- String dics = map.get(nowPoint);
- int pos = dics.indexOf(prePoint);
- int direct = getNextDirect(nowPoint, prePoint, directStr);
- if (direct == -1)
- return "";
- return dics.substring(pos + direct, pos + direct + 1);
- }
- private int getNextDirect(String nowPoint, String prePoint, String directStr) {
- int res = 1;
- String dics = map.get(nowPoint);
- boolean isTwo = true;
- if (dics.length() == 7) {
- isTwo = false;
- }
- int len = directStr.length() / 2;
- int pos = this.count % len;
- String ditStr = "TT";
- while (ditStr.equals("TT")) {
- ditStr = directStr.substring(pos, pos + 1);
- if (repeat.containsKey(prePoint + nowPoint + ditStr + pos))
- return -1;
- else
- repeat.put(prePoint + nowPoint + ditStr + pos, "");
- if (isTwo) {
- this.count++;
- } else {
- ditStr = directStr.substring(pos, pos + 2);
- pos += 2;
- pos = pos % len;
- this.count += 2;
- }
- }
- if (isTwo) {
- if ("H".equals(ditStr))
- res = 1;
- else
- res = 2;
- } else {
- if ("HH".equals(ditStr))
- res = 1;
- else if ("HT".equals(ditStr))
- res = 2;
- else
- res = 3;
- }
- System.out.print("[" + ditStr + "]/t");
- return res;
- }
- private void initMap() {
- map = new HashMap<String, String>();
- map.put("A", "#BF#B");
- map.put("B", "AGCAG");
- map.put("C", "BGDBG");
- map.put("D", "CHECH");
- map.put("E", "DKFDK");
- map.put("F", "ELAEL");
- map.put("G", "BIHCBIH");
- map.put("H", "GJDGJ");
- map.put("I", "GMJGM");
- map.put("J", "IMKHIMK");
- map.put("K", "JNLEJNL");
- map.put("L", "KNFKN");
- map.put("M", "INJIN");
- map.put("N", "MLKML");
- }
- }
我觉得本题只要解决两个基本问题后就比较简单了,一个是如何建模来方便的处理转向的问题,另一个就是如何判断当前的走法是一种死循环(永远到不了Home)。
1、第一个问题比较麻烦的地方是,左右是与行驶的方向相关的,为了避免每次都考虑行驶的方向,程序中建立的一个map存储了所有节点的方向信息,例如对于节点B,存储的是"AGCAG",顺序是“后、上、前、下、后、上、前”如果像B一样没有前向节点那么就是“后、上、下、后、上”,Home节点以"#"代表。
2、第二个问题,程序中维护一个map,如果当前节点的“形式”存在于该map中,那么就认为是重复。这种“形式”为,前一个节点+当前节点+方向+选择的硬币在整个序列中的位置。