昨天5点爬起来赶火车,下午到自己窝打扫一通卫生塞了几口饭后就北京瘫了。。。困意和懒惰占了上风,神志恍惚到晚上十一点多,看了眼存款余额,立刻爬起来想做几道题,结果才看了一道题思考该怎么做的过程中就睡着了( ╯□╰ )。。。
今早爬起来接着做了一通清洁工作,去营业厅排队交个网费,去超市买了堆吃的,美好的一上午就又没了(虽然在工作日逛超市很爽,但想到别人现在正在办公室中努力奋斗(主要是有收入)心情又暗淡了。。。)。
下午终于坐回电脑前接着想昨天那道题。
1.已知一个2元数组,这个数组的构成为:每行代表一个人,第一列代表这个人的身高,第二列代表在这个数组中另外有几个人的身高大于等于这个人的身高。求将这个数组重新排序,让这个数组符合它想要表达的逻辑。
思路:(别人的)1.先对数组按照身高排序,身高相同的情况按照第二列排序,此时会得到身高最高的1位或2位;2.再将剩下的人按照第二列的顺序插入到1中排好的队列中。
通过这道题又知道了一个c#中的数据结构:Tuple类
MSDN Tuple类
(Tuple类提供了一个创建元组对象的静态方法,但它本身不是元组对象,它只是提供了一个可以实例化元组对象而不用显式指明每个元组的类型的创建方法,比如:
var peple = new Tuple<string, int, int, int>("Alice", 18, 98, 1); //名字,年龄,分数,名次
//第i元组可以用Itemi表示,比如Item1,Item2...
言归正传,此题的代码:
int[,] ReconstructQueue(int[,] people)
{
List<Tuple<int, int>> list1 = new List<Tuple<int, int>>();
List<Tuple<int, int>> list2 = new List<Tuple<int, int>>(people.GetLength(0)) //最后按第二列排序的时候用
for(int i = 0; i < people.GetLength(0); i++)
{
list1.Add(new Tuple(people[i,0], people[i,1]);
}
//List的排序当元素比较少的时候是不稳定排序,所以当元素相等时不一定能保证相等元素的顺序,所以自定义按第一列数字大小降序第二列升序的排序方法
list1.Sort((x,y)=> int result = y.Item1.CompareTo(x.Item1); return result == 0 ? x.Item2.CompareTo(y.Item2):result);
//最后将排好序的每组数据按照第二列的顺序插入到list2中
for(int i = 0; i < list1.Count; i++)
{
list2.Insert(list1[i].Item2, list1[i]); //在list1[i]的第二列的数表示的位置上插入list1[i]
}
//因为要求返回的是数组,所以将list2再转为数组
for(int i = 0; i < people.GetLength(0); i++)
{
people[i, 0] = list2[i].Item1;
people[i, 1] = list2[i].Item2;
}
return people;
}
2.已知一棵二叉树,求该树最后一行最左边结点的值(默认参数root为非空)
思路:既然新知道了一个好用的数据结构,就会迫不及待的想多用几次,这道题想到的是层次遍历(其实就是对递归不熟( ╯□╰ )),用Tuple记下每层的结点和所属层数,然后循环遍历一遍就找到了。
int FindBottomLeftTree(Tree root)
{
Queue q = new Queue();
List<Tuple<Tree, int>> lt = new List<Tuple<Tree,int>>();
int level = 0;
q.Enqueue(root);
while(q.Count > 0)
{
Queue tmp = new Queue();
while(q.Count > 0)
{
Tree t = (Tree)q.Dequeue();
if(t.left != null)
{
tmp.Enqueue(t.left);
lt.Add(new Tuple<Tree, int>(t.left, level));
}
if(t.right != null)
{
tmp.Enqueue(t.right);
lt.Add(new Tuple<Tree, int>(t.right, level));
}
}
q = tmp;
level++;
}
if(level < 3)
{
if(root.left != null)
{
return root.left.value;
}
if(root.right != null)
{
return root.right.value;
}
}
for(int i = lt.Count - 1; i > 0; i--)
{
if(!lt[i].Item2.Equals(lt[i-1].Item2))
{
return lt[i].Item1.value;
}
}
return root.value;
}
然后记一下别人的递归的方法:
int deepestRow;
int num = 0;
int FindBottomLeftTree(Tree root)
{
deepestRow = -1;
num = 0;
FindTree(root, 0);
return num;
}
void FindTree(Tree root, int row)
{
if(root == null)
{
return;
}
FindTree(root.left, row+1);
if(row > deepestRow)
{
deepestRow = row;
num = root.val;
}
FindTree(root.right, row+1);
}
3.已知一个按照由小到大排好序的整数数组,其中除一个数以外的所有数都有两个,比如{1,1,2,2,3,4,4},求这个孤独的数字。重点:要求平均时间复杂度为O(logN),空间为O(1)
思路:时间复杂度为n的是人都能想到,但是为logN的就说明平均循环的步长为2n,如果只是单纯的每次乘2肯定会漏掉很多数字,所以还得从已知的数组的特点入手:
因为数组是按从小到大排好序的,所以重复的数字肯定是挨在一起的,所以那个孤独的数字出现的位置序号肯定是偶数(想到这儿我又断片儿了,还得去答案里膜拜大神的解法( ╯□╰ )。。。)
(大神说)在数组头部设一个指针low,在尾部设一个指针high,然后取两个指针的中间值middle处的数字,如果这个数字与它后边的数不相等,说明从low到middle有奇数个数,那么孤独数一定在low和middle的范围内;如果这个数字与它后边的数相等,则说明孤独数在middle到high的范围内。 m (-__- )))m
int FindSigleElement(int[] nums)
{
int low = 0;
int high = nums.Length - 1;
while(low < high)
{
int middle = (low + high) / 2;
if(middle % 2 == 1)
{
middle--; //确保middle为偶数
}
if(nums[middle] != nums[middle+1])
{
end = middle;
}
else
{
start = middle + 2;
}
}
return nums[end];
}