算法总结四

在笔试写算法时候应该注意的问题:

1,如果函数传入的形参时个0或者负数怎么处理,传入第k个元素不在队列中怎么办

2, 一个数如果相加或者相乘后很大超过了该类型的范围怎么办

3,数组存不下怎么办,越界问题


鲁棒性:也即程序的健壮性,当输出非法字符,对于数组越界等错误进行检验不让程序崩溃


最初想法:先遍历一边链表得到有几个数,再遍历一次链表,第n-k+1个节点记为结果

另一种更简化算法:使用两个指针,命名为前指针和后指针,前指针移动到第k个位置,后指针放到链表起始位置,让两个指针一起向前移动,当前指针移动到链表尾部next为空时,后指针记为所求


存在三个问题:





在c#中这样foreach移除数据是不对的

foreach (string s in myString) 

myString.Remove(s); 
}

因为foreach是只读的

C#遍历List并删除某个或者几个元素的方法,你的第一反应使用什么方法实现呢?foreach? for?

如果是foreach,那么恭喜你,你答错了。如果你想到的是用for,那么你只是离成功进了一步。

正确的做法是用for倒序遍历,根据条件删除。下面我们用代码来演示foreach,for删除list数据的情况:

List<Students> stuList = new List<Students>();
            stuList.Add(new Students("Tom",20));
            stuList.Add(new Students("Tang", 20));
            stuList.Add(new Students("Tang", 22));
            stuList.Add(new Students("Trista", 24));
            stuList.Add(new Students("Lili", 25));
打印结果:Tom  Tang  Tang  Trista  Lili

1.先用foreach遍历删除姓名为Tang的学生,代码如下:

foreach (var stu in stuList)
{
       if (stu.Name == "Tang")
            stuList.Remove(stu);
}

会报如下错误:


因为在foreach中删除元素时,每一次删除都会导致集合的大小和元素索引值发生变化,从需导致在foreach中删除元素会出现异常。
2.用for正序遍历删除,代码如下:

//删除姓名为Tang的学生
            for (int i=0;i< stuList.Count;i++)
            {
                if (stuList[i].Name == "Tang")
                    stuList.Remove(stuList[i]);
            }

只删除了一个姓名为Tang的学生。为什么会出现这种情况呢?

这是因为当i=1时,满足条件执行删除操作,会移除第一个Tang,接着第二个Tang会前移到第一个Tang的位置,即游标1对应的是第二个Tang。

接着遍历i=2,也就跳过第二个Tang。

3.用for倒序遍历删除,代码如下:

for (int i = stuList.Count-1; i>=0; i--)
            {
                if (stuList[i].Name == "Tang")
                    stuList.Remove(stuList[i]);
            }

这段摘自:http://www.cnblogs.com/qk2014/p/4764073.html



比如我把树初始化成这样:要取得所有和为20的子树

这里有个细节;

从左孩子节点递归回来需要把所有路径中包含左孩子的节点都去除,因为如果不去除那么下面新的右孩子要怎么放?

也即遍历到9节点时会有10,5,6,9和5,6,9和6,9和9这4种子树,那么9退出回到6需要把9节点全部剔除,为10,5,6和5,6和6一共3种子树,然后才能添加右孩子14

从右孩子递归回来需要把所有路径中包含右孩子的节点都去除,


输出


我的C#代码:

static void Main(string[] args)
        {
            Node node = new Node();
            node.left = new Node();
            node.right = new Node();
            node.right.left = new Node();
            node.left.left = new Node();
            node.left.right = new Node();
            node.left.left.left = new Node();
            node.left.left.right = new Node();
            node.left.right.left = new Node();
            node.left.right.right = new Node();

            node.value = 10;
            node.left.value = 5;
            node.right.value = 7;
            node.right.left.value = 3;
            node.left.left.value = 6;
            node.left.right.value = 9;
            node.left.left.left.value = 9;
            node.left.left.right.value = 14;
            node.left.right.left.value = 4;
            node.left.right.right.value = 6;
            List<List<int>> list = new List<List<int>>();
            list = GetResult(node, 20);
            foreach (List<int> l in list1)
            {
                foreach (int i in l)
                {
                    Console.Write(i);
                }
                Console.WriteLine();
            }
            Console.ReadKey();
        }
        static List<List<int>> list1 = new List<List<int>>();//最终输出的list
        static List<List<int>> list2 = new List<List<int>>();//保存当前节点之前的所有子树

        static List<List<int>> GetResult(Node node,int num)
        {
            if (num<=0)
            {
                return list2;
            }
            if(node==null){
                return list2; ;
            }
            for (int i=0;i<list2.Count;i++ )
            {
            //    if (list2[i].Count>0)  //这里为什么要加上这个条件,比如list2大小为2,list2[1]为4,那么remove掉list2[1]后为0,大小还是2,这里非常注意
           //     {
                    list2[i].Add(node.value);//每条路径都添加上当前值(每个子树都加上新节点)
            //    }
                //这里就开始进入判断条件了,取出每个list的可能,如果所有元素之和等于num就添加到list1中
                int tempNum = 0;
                for (int j=0;j<list2[i].Count;j++)
                {
                    tempNum += list2[i][j];
                }
                if (tempNum==num)
                {
                    List<int> list9 = new List<int>();
                    //这里非常注意,或许你想直接list1.add(list2[i])但是注意了,这个list2[i]每个元素是个list,也即把引用给了list1,
                    //也即浅拷贝,所以后面删除左子树的时候,删掉了list2[i]一部分内容,那么list1中也跟着删除了,所以要深拷贝
                    for (int k=0;k<list2[i].Count;k++)
                    {
                        list9.Add(list2[i][k]);
                    }
                    list1.Add(list9);
                }
            }
            //遍历完后创建把新节点添加到list2中,看这个节点是否==num
                List<int> list = new List<int>();
                list.Add(node.value);   //新创建一个list保存该节点的值
                list2.Add(list);
               if (node.value == num)
               {
                List<int> list9 = new List<int>();
                list9.Add(node.value);
                list1.Add(list9);
               }
            List<List<int>> list3 = new List<List<int>>();//保存左孩子当前的路径
            List<List<int>> list4 = new List<List<int>>();//保存右孩子当前的路径
            list3 = GetResult(node.left,num);  //递归左节点和右节点
            if (node.left != null)//看有没有左孩子,有就删除list2中的所有路径中所有左孩子节点 
            { 
                for (int i=0 ; i<= list3.Count - 1; i++)
               { 
                    if (list3[i].Count - 1>=0) //这里非常注意的是.Count-1可能为-1的情况,那么要保证数组不会越界,必须要对异常处理  
                    {
                        
                            list3[i].Remove(list3[i][list3[i].Count - 1]);
                        if (list3[i].Count==0)//如果删除节点后list3中元素的Count为0,那么就删除该元素保证list3中Count正确
                        {
                            list3.Remove(list3[i]);
                        }
                    }
                }
            }
            list4 = GetResult(node.right, num);
            if (node.right != null)//看有没有右孩子,有就删除list2中的所有路径中所有右孩子节点 
            {
                for (int i=0; i <= list4.Count - 1; i++)
                { 
                    if (list4[i].Count - 1 >= 0)
                    {
                        list4[i].Remove(list4[i][list4[i].Count - 1]);
                        if (list4[i].Count == 0)
                        {
                            list4.Remove(list3[i]);
                        }
                    }
                }
            }
        //    for (int i=0;i<list3.Count;i++)
        //    {
        //        list1.Add(list3[i]);
       //         list3.Remove(list3[i]);  //这里不知道怎么回事,不remove掉list3.Count一直增加
       //     }
         //   for (int j = 0; j < list4.Count; j++)
        //    {
         //       list1.Add(list4[j]);
       //         list4.Remove(list4[j]);
       //     }
            return list4;
        }
    }

其实这里没必要new出list3和list4,全部改成list2也可以,返回值为空,因为list2是静态的所以不用接收也是可以的


假如list2中有5个元素,假如后三个元素也即后三个list中元素全部移去,那么后三个list为空,但是list2中仍然引用了后三个list,也即保存了后3个空地址,所以list2中count仍然是5,可以再遍历一遍,如果元素的大小为空就移除该元素,那么count就变为2了



我用list里面放list形式,外面的list放当前节点的所有路径,内层放其中的一种可走路径,下面这段代码好好看下:

if (tempNum==num)
                {
                    List<int> list9 = new List<int>();
                    //这里非常注意,或许你想直接list1.add(list2[i])但是注意了,这个list2[i]每个元素是个list,也即把引用给了list1,
                    //也即浅拷贝,所以后面删除左子树的时候,删掉了list2[i]一部分内容,那么list1中也跟着删除了,所以要深拷贝
                    for (int k=0;k<list2[i].Count;k++)
                    {
                        list9.Add(list2[i][k]);
                    }
                    list1.Add(list9);
                }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值