一、#23:合并K个排序链表
题目要求,和前面那个题目一样,有序链表的排序,之前是两个链表元素大小排序,现在是K个链表元素大小排序,但是我们可以把问题抽象成两两排序然后继续两两排序,如此递归下去,首先还是常规操作,排除特殊情况,那就是输入为0和1的时候,返回NULL或者唯一的链表,当链表个数大于等于2的时候,则需要进行递归两两比较
设置的递归形式为寻找到两个链表进行比较,递归的主体函数较为简单,是对两个链表进行排序的算法:
ListNode* mergeNode(ListNode* node_1,ListNode* node_2)
{
ListNode* head=new ListNode(0);
ListNode* node=head;
while(node_1!=NULL&&node_2!=NULL)
{
if(node_1->val<node_2->val)
{
node->next=node_1;
node=node->next;
node_1=node_1->next;
}
else
{
node->next=node_2;
node=node->next;
node_2=node_2->next;
}
}
if(node_1==NULL&&node_2==NULL)
return head->next;
if(node_1==NULL)
node->next=node_2;
else
node->next=node_1;
return head->next;
}
具体原理在之前那个题目已经写过了,常规的有序链表归并排序,关键就在怎么设计寻找递归结点的函数上,首先为了减少时间复杂度,我想到了用二分法,这样递归一半即可完成全部遍历,当设置的两个结点挨着的时候则输出前结点参与两节点归并,若是两个结点不挨着,则需要继续去二分法,知道找到相邻结点才输出,结点递归代码如下:
ListNode* merge(vector<ListNode*>& lists,int first,int last)
{
if(last-first==1)
return lists[first];
else
return mergeNode(merge(lists,first,first+(last-first)/2),merge(lists,first+(last-first)/2,last));
}
总之一句话,不找到相邻结点就一直二分下去!运行速度和时间只有40%+的超过率,看了大佬的程序,还是分治法速度快,便于操作,直接用堆去解决问题,牛批,下面贴上我的二分递归法全部代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int len=lists.size();
if(len==0)
return NULL;
if(len==1)
return lists[0];
return mergeNode(merge(lists,0,len/2),merge(lists,len/2,len));
}
ListNode* mergeNode(ListNode* node_1,ListNode* node_2)
{
ListNode* head=new ListNode(0);
ListNode* node=head;
while(node_1!=NULL&&node_2!=NULL)
{
if(node_1->val<node_2->val)
{
node->next=node_1;
node=node->next;
node_1=node_1->next;
}
else
{
node->next=node_2;
node=node->next;
node_2=node_2->next;
}
}
if(node_1==NULL&&node_2==NULL)
return head->next;
if(node_1==NULL)
node->next=node_2;
else
node->next=node_1;
return head->next;
}
ListNode* merge(vector<ListNode*>& lists,int first,int last)
{
if(last-first==1)
return lists[first];
else
return mergeNode(merge(lists,first,first+(last-first)/2),merge(lists,first+(last-first)/2,last));
}
};
二、CNN
卷积神经网络的先进性主要是和全连接神经网络进行对比,全连接神经网络在处理上会很慢,举个例子,比如处理32*32的图片,隐藏层节点定义为500,则第一层需要32*32*500+500个节点,因为需要全连接,而卷积神经网络就会极大优化!
结构组成:
1.输入层:输入层一般代表一张图片的像素矩阵,比如传入一张图片,他的长和宽代表图像的大小,三维矩阵的深度代表图像的彩色channel,黑白的channel为1,彩色的channel为3,从输入层开始,卷积神经网络会把这一层的三维矩阵不断转化为下一层的,最后才通过全连接层。
2.卷积层:卷积层的每个节点的输入只是上一层神经网络的一小块,而全连接层则是所有,这里很明显就减少了很多工作量,卷积层处理后的节点矩阵会变得更深,卷积的计算一般要通过3*3或者5*5的filter,计算过程也较为简单,但是根据步长的不同 结果也不同
3.池化层(pooling):池化层不改变三维矩阵的深度,但是可以缩小矩阵的大小,用比较通俗的例子来说就是可以吧一张分辨率很高的图片转化为分辨率很低的图片,通过池化层可以进一步减小全连接层节点的个数,使得整个神经网络的参数大大减少,maxpooling其实也就是根据filter的大小进行一个分块取最大值的操作,类似于一个最大采样过程,不断提取图像的特征~
4.全连接层:在前面要经过很多层卷积和pooling,最后会通过一到两个全连接层来给出最后的分类结果,全连接层的作用就是分类
5.Softmax层:用于分类问题,类似于knn和线性回归,也是一种回归方法,Softmax 在机器学习和深度学习中有着非常广泛的应用。尤其在处理多分类(C > 2)问题,分类器最后的输出单元需要Softmax 函数进行数值处理。
将CNN结构用在网络模型中,无非就是加了多个卷积和池化,自己开发新的网络模型很艰难。。。所以基本都是在已有网络模型框架上进行改造创新,常用的有LeNet、ResNet、VGG16、Inception,我在上次图像语义分割比赛中用到了VGG16和RESNET,但是基于基础知识的匮乏,框架也改不动啊。。。很难受,所以现在加强基础很有必要!
今天回去和我宝视频咯,明儿实践TF的迁移学习~~~