[编程] 行动序列 面试 算法 (五)

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * 假设你站在一个无限大的平面的某一点上,接下来你要按照收到的指令序列依次循环执行。每条指令可能是以下三种之一:
 * S:前进一步,R:向右转90度,L:向左转90度。
 * 现在需要你写一个算法,判断对于给定的指令序列,是否存在“绕圈子”的现象。
 * 所谓“绕圈子”是指:当你无限循环执行给定的指令序列后,存在一个有限的正整数R,使得你所有经过的点都在以初始点为圆心,以R步长度为半径的圆内。另外,我们假设,每一步的长度都是相同的。
 *
 * 输入:
 * 第一行为一个整数n
 * 之后一共有n行,每行为一个指令序列
 *
 * 输入约束:
 * n位于区间[1,50]
 * 从第二行开始,每行字符串长度为1-50,且仅包含字母L, S, R
 *
 * 输出:
 * 仅有一个单词。
 * 按照输入给定的顺序,从第一行开始,每行从第一个字符开始。如果给定的指令序列存在绕圈子的现象,则输出bounded,否则输出unbounded
 *
 * 举例1:
 * 输入
 * 1
 * SRSL
 * 输出
 * unbounded
 * 解释:假设你初始状态向北,你的行动序列依次为前进,右转,前进,左转,此时你仍然向北,但位置已经向东北方挪动了。只要时间足够长,你会一直向东北方前进,所以你没有在绕圈子。
 *
 * 举例2:
 * 输入
 * 2
 * SSSS
 * R
 * 输出
 * bounded
 * 解释:你会一直绕着一个边长为4步的小正方形循环行进,所以你在绕圈子
 */
public class X {
    static List<String> list = new ArrayList<>();
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int c = scanner.nextInt();
        String str = c + "";
        while (c > 0){
            str += " " + scanner.next() ;
            c --;
        }
        // 以上只是拼接处字符串 例: 1 SSSL
        System.out.println(test(str));
    }
    static String test(String str) {
        String strs[] = new String[1];
        if (str.indexOf(" ") != -1)  strs = str.split(" ");
        else strs[0] = str;
        while (list.size() < 4) {
            for (int i = 1;i<strs.length;i++){
                String comd = strs[i];
                for (int j = 0; j < comd.length(); j++) {
                    changeN(comd.charAt(j));
                }
            }
            // 走完一次指令集,记录坐标点
            list.add(x + "," + y);
        }
        int count = 0;
        for (String s : list) if (s.equals("0,0")) count ++;
        return count > 0 ? "bounded" : "unbounded";
    }
    static char n = 'S';
    static int x = 0, y = 0;
    /**
     * n = S X Z Y 上下左右 表示当前移动方向
     * 默认S 向上走
     * 默认坐标 x = 0, y = 0;
     * @param c  S R L 3中可能
     */
    static void changeN(char c) {
        switch (c) { // 指令方向
            case 'S': // 只有S才会变更坐标, 其他情况之变化方向
                switch (n) {
                    case 'S': y ++; break;
                    case 'X': y--; break;
                    case 'Z': x--; break;
                    case 'Y': x++; break;
                }
                break;
            case 'R':
                switch (n) {
                    case 'S': n = 'Y'; break;
                    case 'X': n = 'Z'; break;
                    case 'Z': n = 'S'; break;
                    case 'Y': n = 'X'; break;
                }
                break;
            case 'L':
                switch (n) {
                    case 'S': n = 'Z'; break;
                    case 'X': n = 'Y'; break;
                    case 'Z': n = 'X'; break;
                    case 'Y': n = 'S'; break;
                }
                break;
        }
    }
    /**
     * 解题思路
     * 无论指令有多少行,序列有多少步骤,跑一轮下来其实就是相对于原始位置有了一个方向和坐标差的变化,
     * 跑第二轮下来,跟第一轮的终点也是相同的变化量,只是方向变了
     * 所以可以把完整一轮当做是一步,可以完整跑一轮,记录下来变化的方向和坐标差,
     * 下一轮跑的时候就直接计算终点 而不用再跑一遍指令集 (有时间在优化下)
     * 这样的四步之后的方向还是初始方向,所以这四步也就是是一个周期,只要判断第一个周期下来和第二个周期下来相对于原始点的位移是不是增加了,
     * 就知道会不会绕圈子
     */
}

  

原文地址:https://www.cnblogs.com/412013cl/p/11768277.html