在笔试写算法时候应该注意的问题:
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); }
会报如下错误:
//删除姓名为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是静态的所以不用接收也是可以的
我用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);
}