zoukankan      html  css  js  c++  java
  • <<薪资至少10K的一道题,你能拿下吗>>练习

      偶尔要写写算法,是我平时用来保持感觉的常用的方法.今天看到园子里一面试题,看了一下感觉也能实现,不过过程确实艰的,自认为自己对算法的感觉还不错.不过这题确实我也用了差不多一下午的时间,基本上把工作时间都耗掉了.主要的两个方法已经搞定,下面先说一下思想,代码确实不太重要,因为过一周我自己就会看不懂了,就像我今天也去看以前的代码.因为这里用到一部分深度优先遍历,所以去找以前代码,但是完全没有作用,还是纯写.

      

        interface IPath
        {
            /// <summary>
            /// 增加某条地铁线路
            /// </summary>
            /// <param name="lineNo">地铁线号</param>
            /// <param name="stationNum">站点数目</param>
            /// <param name="stationArray">地铁线站台号数组</param>
            void AddLine(int lineNo, int stationNum, int[] stationArray);
    
            /// <summary>
            /// 计算从超点到终点的最短路线长度
            /// </summary>
            /// <param name="srcStation">起点站</param>
            /// <param name="desStation">终点站</param>
            /// <returns>起点站到终点站最短线长度</returns>
            int CalcMinPathLen(int srcStation, int desStation);
    
            /// <summary>
            /// 输出从起点到终点的最短路线
            /// </summary>
            /// <param name="srcStation">起点</param>
            /// <param name="desStation">终点</param>
            /// <param name="pathNum">条数</param>
            /// <param name="pathLen">长度</param>
            /// <param name="pathes">结果路线集合</param>
            /// <returns>0成功 -1出错</returns>
            int SearchMinPaths(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes);
    
            /// <summary>
            /// 最优路线
            /// </summary>
            /// <param name="srcStation">起点</param>
            /// <param name="desStation">终点</param>
            /// <param name="pathNum">条数</param>
            /// <param name="pathLen">长度</param>
            /// <param name="pathes">结果路线集合</param>
            /// <returns>0成功 -1出错</returns>
            int SearchBestPathes(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes);
    
        }

    其实这个从题目中命名等看出来主要是C++题,本人用C#实现,其实可以改一些参数名称更为方便,但是这里就按题目中接口来吧.AddLine方法就不说了.

    int CalcMinPathLen(int srcStation, int desStation);

    计算最短路径,这里用的是迪杰斯特拉算法,就是从起点按起点到各各点最短距离来一个一个往集合里面添加,当然这里的距离就是1,如果是其它数字也是可以的.

    int SearchMinPaths(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes);

    这个方法其实略坑了,我基本上是重新想的解决办法,同第一个方法没有很大的联系,不知道我这种思考是否是最优的,不过是可以解决的.重点地方就是用到一个变异的深度优先遍历,这个是有环路存在的,所以比树的深度优先遍历要复杂一些,注意一下深度就可以了,用到一个深度变量去控制是不是保留在遍历排除集合中,就是方法中的list.

    两个方法代码如下

        public class MetroPath : IPath
        {
            private readonly List<Tuple<int, int, int[]>> pathes;
            private int stationCount = 0;
    
            private List<int> minStations;
    
            public MetroPath()
            {
                pathes = new List<Tuple<int, int, int[]>>();
                minStations = new List<int>();
            }
    
    
            public void AddLine(int lineNo, int stationNum, int[] stationArray)
            {
                if (stationNum < 2 || stationArray == null || stationArray.Length != stationNum)
                    Console.WriteLine("站点数目不对");
                else
                    pathes.Add(new Tuple<int, int, int[]>(lineNo, stationNum, stationArray));
            }
    
            public int CalcMinPathLen(int srcStation, int desStation)
            {
                //用迪杰斯特拉算法计算
                Dictionary<int, int> stationLens = new Dictionary<int, int>();
    
                IEnumerable<int> ct = pathes[0].Item3;
                //得到所有站数
                foreach (var a in pathes)
                {
                    ct = ct.Union(a.Item3);
                }
                stationCount = ct.Distinct().Count();
    
                try
                {
                    stationLens.Add(srcStation, 0);//初始
    
                    while (stationLens.Count < stationCount)
                    {
                        stationLens = FindMinStation(stationLens, srcStation);
                    }
    
                    //下一题用
                    minStations = stationLens.Select(x => x.Key).ToList();
    
                    //找出起点到终点最短长度 
                    return stationLens[desStation];
                }
                catch
                {
                    return -1; //出错
                }
            }
    
            //找出余下站点中最短的站点及起点到它的长度
            private Dictionary<int, int> FindMinStation(Dictionary<int, int> stations, int srcStation)
            {
                Dictionary<int, int> lens = new Dictionary<int, int>();
    
                foreach (var p in pathes)
                {
                    foreach (var station in p.Item3)
                    {
                        if (!stations.ContainsKey(station))
                        {
                            //计算最小值
                            var minlen = ReachLen(stations, srcStation, station);
                            if (minlen > 0 && !lens.ContainsKey(station))
                                lens.Add(station, minlen);
                        }
                    }
                }
    
                //找出lens中最小的(可以多个)加入集合
                int min = lens.Min(v => v.Value);
    
                return stations.Union(lens.Where(x => x.Value == min)).ToDictionary(k => k.Key, v => v.Value);
            }
    
            //是否是可达的 -1为不可达
            private int ReachLen(Dictionary<int, int> stations, int srcStatoin, int station)
            {
                List<int> reachStations = new List<int>();
                foreach (var p in pathes)
                {
                    for (int i = 0; i < p.Item3.Length; i++)
                    {
                        if (p.Item3[i] == station)
                        {
                            if (i - 1 >= 0 && !reachStations.Contains(p.Item3[i - 1]))
                                reachStations.Add(p.Item3[i - 1]);
                            if (i + 1 < p.Item3.Length && !reachStations.Contains(p.Item3[i + 1]))
                                reachStations.Add(p.Item3[i + 1]);
                        }
                    }
                }
    
                var q = stations.Where(v => reachStations.Contains(v.Key));
                //相邻点不在集合里面
                if (q == null || q.Count() <= 0)
                    return -1;
                else
                {
                    //找出q中最小的值
                    return q.OrderByDescending(v => v.Value).First().Value + 1;
                }
    
            }
    
    
            public int SearchMinPaths(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes)
            {
                pathNum = 0;
                pathLen = 0;
                pathes = null;
    
                try
                {
                    pathLen = CalcMinPathLen(srcStation, desStation);
    
                    List<int[]> result = new List<int[]>();
    
                    Stack<int> sk1 = new Stack<int>();
                    List<Tuple<int, int>> list = new List<Tuple<int, int>>();
    
                    sk1.Push(srcStation);
                    minStations.Remove(srcStation);
    
                    int ct = 0;
                    int deepth = 1;
                    while (deepth > 0)
                    {
                        bool flag = false;
                        foreach (var x in minStations)
                        {
                            list.RemoveAll(v => v.Item1 > deepth);
    
                            if (ExistsRalation(sk1.Peek(), x) && !sk1.Contains(x) && list.Where(v => v.Item2 == x).Count() <= 0)
                            {
                                sk1.Push(x);
                                deepth++;
                                flag = true;
                                break;
                            }
                        }
    
                        //
                        if (sk1.Peek() == desStation)
                        {
                            //一条完整的路线
                            result.Add(sk1.Reverse().ToArray());
                            deepth--;
                            list.Add(new Tuple<int, int>(deepth, sk1.Pop()));
                            ct++;
                        }
                        //没有找到
                        if (!flag)
                        {
                            deepth--;
                            list.Add(new Tuple<int, int>(deepth, sk1.Pop()));
                        }
                    }
    
                    pathNum = ct;
                    pathes = result.ToArray();
                    return 0;
                }
                catch
                {
                    return -1;
                }
    
            }
    
            private bool ExistsRalation(int a, int b)
            {
                if (a == b)
                    return false;
    
                foreach (var p in pathes.Where(x => x.Item3.Contains(a) && x.Item3.Contains(b)))
                {
                    for (int i = 0; i < p.Item3.Length; i++)
                    {
                        if (p.Item3[i] == a)
                        {
                            if (i - 1 >= 0 && p.Item3[i - 1] == b)
                                return true;
                            if (i + 1 < p.Item3.Length && p.Item3[i + 1] == b)
                                return true;
                        }
                    }
                }
                return false;
    
            }
    
            public int SearchBestPathes(int srcStation, int desStation, out int pathNum, out int pathLen, out int[][] pathes)
            {
                throw new NotImplementedException();
            }
        }
    View Code

    最后一个方法还没有实现,不过大思路也还是可以有的,路径找出来了,只要看路径上交乘点多少就可以了,越少越优,这个算简单.没有时间写了.

    最后是调用代码和结果

                //测试
                IPath mp = new MetroPath();
                mp.AddLine(1, 5, new int[] { 1, 2, 3, 4, 5 });
                mp.AddLine(2, 5, new int[] { 1, 10, 9, 7, 6 });
                mp.AddLine(3, 3, new int[] { 5, 7, 8 });
                mp.AddLine(4, 2, new int[] { 11, 5 });
    
                var min = mp.CalcMinPathLen(1, 11);
                Console.WriteLine("从1到11最短路径长度为:{0}", min);
    
                int pathNum = 0;
                int pathLen = 0;
                int[][] pathes = null;
                var re = mp.SearchMinPaths(1, 11, out pathNum, out pathLen, out pathes);
    
                Console.WriteLine("从1到11最短路径条数为{0},分别是", pathNum);
                foreach (var x in pathes)
                {
                    Console.Write("
    {");
                    foreach (var i in x)
                    {
                        Console.Write("{0},", i);
                    }
                    Console.Write("}
    ");
                }
    
                Console.ReadLine();

    对题中的数据来看是正常的.个人觉得本题还是有难度的,特别是要实实在在写出来,并且调通,我看文中评论有些说简单的人请去实践一下再说吧.

    插个小插曲,就是代码一写过基本上就看不懂了.刚才我说到我查阅深度优先算法,我自己的代码完全看不懂,不过看起来以前写的还是很简练,不过是对简单图的遍历.

            /// <summary>
            /// 深度优先
            /// </summary>
            static void DFS(int[,] a, int n)
            {
                Stack<int> sk1 = new Stack<int>();
                Stack<int> sk2 = new Stack<int>();
                sk1.Push(0);
                Console.WriteLine(0);
                int x = 0;//访问点标记
    
                int ct = 1;//访问节点数
                while (ct < n)
                {
                    int i = 0;
                    bool f = false;
                    for (i = 0; i < n; i++)
                    {
                        if (a[x, i] != 0 && !sk2.Contains(i))
                        {
                            sk1.Push(i);
                            Console.WriteLine(i); ct++;
                            x = i;
    
                            f = true;
                            break;
                        }
                    }
                    if (!f)
                    {
                        //没有找到返回
                        sk2.Push(sk1.Pop());
                        x = sk1.Peek();
                    }
    
    
                }
            }
    View Code

    确实比较短的,不过看不懂.所以主要还是在于思想吧.数据测试

                int[,] a = { 
                           {0,10,0,30,80}
                           ,{0,0,50,0,0}
                           ,{0,0,0,0,10}
                           ,{0,0,20,0,60}
                           ,{0,0,0,0,0}
                       };
    
                Console.WriteLine("DFS:");
                DFS(a, 5);
                Console.Read();

      最后总结:  

        1.理解迪杰斯特拉算法

        2.深度优先遍历,主要用栈,广度优先主要考虑队列.

        3.深度优先的冲突处理,考虑用深度变量.

  • 相关阅读:
    [leetcode]Search for a Range
    Codeforces 432 D. Prefixes and Suffixes
    FZU2127:养鸡场
    安德鲁斯----多媒体编程
    hive RegexSerDe View
    Android 随着输入框控件的清除功能ClearEditText,抄IOS输入框
    Eclipse——热键&amp;Help
    图像形态学操作—腐蚀扩展深度
    基于速度学习机的局部感受野
    Qt:使用Model-View,动态的加载显示数据
  • 原文地址:https://www.cnblogs.com/gw2010/p/4129186.html
Copyright © 2011-2022 走看看