Google编程挑战赛750分题(WordPath)程序拙解及感想

本文分享了Google编程挑战赛750分题(WordPath)的程序解答及感想。作者给出代码实现,指出程序存在采用递归算法效率低、递归函数参数过多等问题,还提到应运用剪枝算法和动态规划优化。最后强调编程需重视数据结构、算法等基础理论。
 Google编程挑战赛750分题(WordPath)程序拙解及感想
作者:yxin1322
 blog: http://blog.csdn.net/yxin1322   转载请注明出处

        上次介绍Google编程挑战赛的文章里已经发了我做的250分题的程序,地址如下:
        今天有时间,再把当时我做的750分的程序发上来,说说我的感想。


题目-Problem Statement
You are given a String[] grid representing a rectangular grid of letters. You are also given a String find, a word you are to find within the grid. The starting point may be anywhere in the grid. The path may move up, down, left, right, or diagonally from one letter to the next, and may use letters in the grid more than once, but you may not stay on the same cell twice in a row (see example 6 for clarification).
You are to return an int indicating the number of ways find can be found within the grid. If the result is more than 1,000,000,000, return -1.
Definition
Class:
WordPath
Method:
countPaths
Parameters:
String[],String
Returns:
int
Method signature:
int countPaths(String[] grid, String find)
(be sure your method is public)
Constraints
-
grid will contain between 1 and 50 elements, inclusive.
-
Each element of grid will contain between 1 and 50 uppercase ('A'-'Z') letters, inclusive.
-
Each element of grid will contain the same number of characters.
-
find will contain between 1 and 50 uppercase ('A'-'Z') letters, inclusive.
Examples
0)
{"ABC",
 "FED",
 "GHI"}
"ABCDEFGHI"
Returns: 1
There is only one way to trace this path. Each letter is used exactly once.
1)
{"ABC",
 "FED",
 "GAI"}
"ABCDEA"
Returns: 2
Once we get to the 'E', we can choose one of two directions for the final 'A'.
2)
{"ABC",
 "DEF",
 "GHI"}
"ABCD"
Returns: 0
We can trace a path for "ABC", but there's no way to complete a path to the letter 'D'.
3)
{"AA",
 "AA"}
"AAAA"
Returns: 108
We can start from any of the four locations. From each location, we can then move in any of the three possible directions for our second letter, and again for the third and fourth letter. 4 * 3 * 3 * 3 = 108.
4)
{"ABABA",
 "BABAB",
 "ABABA",
 "BABAB",
 "ABABA"}
"ABABABBA"
Returns: 56448
There are a lot of ways to trace this path.
5)
{"AAAAA",
 "AAAAA",
 "AAAAA",
 "AAAAA",
 "AAAAA"}
"AAAAAAAAAAA"
Returns: -1
There are well over 1,000,000,000 paths that can be traced.
6)
{"AB",
 "CD"}
"AA"
Returns: 0


我的代码:
1    /*
2             code by: yxin1322
3                date: 2005.12.13
4                blog: http://blog.csdn.net/yxin1322
5               Email: yxin1322@gmail.com
6     */
7    public class WordPath
8    {
9        //题目要求实现的函数
10        public int countPaths(String[] grid, String find)
11        {
12            IntegerHolder TotalFind=new IntegerHolder();//记录单词路径数
13            TotalFind.i=0;
14    
15            for(int i=0; i<grid.length; i++)//对每个值是第一个字母的格执行递归操作
16            {
17                char[] charset=grid[i].toCharArray();
18                for(int j=0; j<charset.length; j++)
19                {
20                    if(charset[j]==find.charAt(0))
21                    {
22                        this.FindCurrent(grid,j,i,find,0,TotalFind);
23                    }
24                }
25            }
26            if(TotalFind.i > 1000000000)//如果结果大于1000000000则返回-1
27            {
28                return -1;
29            }
30            return TotalFind.i;
31        }
32    
33        /*递归回溯函数
34    
35          参数说明:
36                    String[] grid : 装有字母的表格
37                     int CurrentX : 当前搜索的格子的横坐标
38                     int CurrentY : 当前搜索的格子的纵坐标
39                      String find : 需要查找的字符串
40             int CurrentFindIndex : 当前查找到字符串中的第几个字符
41          IntegerHolder TotalFind : 记录查找到的路径数
42        */
43        public void FindCurrent(String[] grid, int CurrentX, int CurrentY, String find,
44                                 int CurrentFindIndex, IntegerHolder TotalFind)
45        {
46            //判断当前格是否超过表格边界
47            if((CurrentX>=0 && CurrentX<grid[0].length()) && (CurrentY>=0 && CurrentY<grid.length))
48            {
49                //判断当前格内的字符是否与待查找的字符相同
50                if(grid[CurrentY].charAt(CurrentX)==find.charAt(CurrentFindIndex))
51                {
52                    if(CurrentFindIndex==find.length()-1)//判断是否已经匹配完整个字符串
53                    {
54                        TotalFind.i++;
55                    }
56                    else//若还没匹配完整个字符串,则搜索当前格的其他八个方向,递归求解
57                    {
58                            FindCurrent(grid, CurrentX-1, CurrentY-1, find, CurrentFindIndex+1, TotalFind);
59                            FindCurrent(grid, CurrentX, CurrentY-1, find, CurrentFindIndex+1, TotalFind);
60                            FindCurrent(grid, CurrentX+1, CurrentY-1, find, CurrentFindIndex+1, TotalFind);
61                            FindCurrent(grid, CurrentX+1, CurrentY, find, CurrentFindIndex+1, TotalFind);
62                            FindCurrent(grid, CurrentX+1, CurrentY+1, find, CurrentFindIndex+1, TotalFind);
63                            FindCurrent(grid, CurrentX, CurrentY+1, find, CurrentFindIndex+1, TotalFind);
64                            FindCurrent(grid, CurrentX-1, CurrentY+1, find, CurrentFindIndex+1, TotalFind);
65                            FindCurrent(grid, CurrentX-1, CurrentY, find, CurrentFindIndex+1, TotalFind);
66                    }
67                }
68                else//若当前格内的字符不与待查找的字符相同,则回溯返回上层调用函数
69                {
70                        ;
71                }
72            }
73            else//若当前格超出表格边界,则回溯返回上层调用函数
74            {
75                    ;
76            }
77        }
78    
79        //测试函数
80        public static void main(String[] args)
81        {
82            String[] grid={"ABABA",
83                           "BABAB",
84                           "ABABA",
85                           "BABAB",
86                           "ABABA"};
87    
88            String find="ABABABBA";
89            WordPath wp=new WordPath();
90            int result=wp.countPaths(grid,find);
91            System.out.println("Returns: "+result);
92    
93        }
94    
95        //将int类型的变量封装成类,方便int类型作为函数参数时能引用传递
96        static class IntegerHolder
97        {public int i;}
98    }

        这个程序完全实现了题目的逻辑,但在诸多方面都存在着不足,我个人认为有一下几个方面:
        1、采用了递归算法。这样做可以使代码简洁短小,但也会使程序在递归过深时效率低下。在本题中,递归的调用层数与搜索的字符串长度相同,所以我的程序在搜索长字符串时(比如测试数据5中的“AAAAAAAAAAA”),效率很低。如果有可能的话,可以考虑把递归转换成循环来做。
        2、递归函数的参数过多。递归函数参数过多会影响执行效率,我写的这个递归函数中总共用到了6个参数,其中第一个和最后一个都可以做为全局变量(类成员变量)来定义,而不用每次递归都向里传。递归中导致无谓的参数压栈,是以后应该避免的。
        3、题目要求当答案超过1000000000时,返回-1。我的做法是等全部统计完后再判断答案是否大于100000000,若大于1000000000则返回-1。仔细想来,如果程序已经算到了一个准确的数字,又何必返回-1呢?所以题目的本意是在答案超过1000000000时就可以立即返回-1,而不用继续无谓的计算。更超前一点地想,其实1000000000已经是一个很大的数了,一个程序要计算找出1000000000个路径,肯定要超过大赛2秒的时限。所以要真正做好这题还要用到剪枝算法和动态规划,这几天查了一些讲剪枝算法和动态规划的文章,有了一些认识,但还是没有思路用这些思想来改造我的程序,只有等以后认识加深后再改了。
         经过这次竞赛感受最深的是数据结构、操作系统、编译原理、算法这些基础理论在编程过程中还是比较重要的,缺少了理论基础,要写出一些复杂而又不失效率的程序是不可能的,往往顾此失彼。对照自己,发觉自己虽然对数据结构、编译原理这些课程都比较熟悉,但缺乏理性而深入的认识,缺少灵活地运用,知其然而不知其所以然的居多。以后在不断实践的同时还要继续加强基础理论的学习,否则以后毕业后只能写简单逻辑,拖控件写事件,那就和社会上电脑学校三个月毕业的学生没区别了。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值