数据结构与算法

1.将一个含有n个元素的数组向右循环移动k位,要求时间复杂度是O(n),且只能使用两个额外的变量。

右移K位的过程就是按后K位和剩余位分成两部分,分别逆序排列,然后把整个数组逆序排列。

变换过程通过以下步骤完成:

1.逆序排列 abcd: abcd1234 -> dcba1234;

2.逆序排列 1234: dcba1234-> dcba4321;

3.全部逆序 dcba4321->1234abcd。

2.单链表反转

https://blog.csdn.net/sicofield/article/details/8850269#

方法1:将单链表储存为数组,然后按照数组的索引逆序进行反转。

方法2:使用三个指针遍历单链表,逐个链接点进行反转。

Node * ReverseList(Node *head)
{
	Node *p1,*p2,*p3;
	if(head==NULL||*head==NULL)
	return head;
	p1=head;
	p2=p1->next;
	while(p2)             //注意条件
	{
		p3=p2->next;	      //要改变p2->next的指针,所以必须先保留p2->next	     
		p2->next=p1;
		p1=p2;		      //循环往后
		p2=p3;
	}
	head->next=NULL;   //原先的head已经变成tail,别忘了置空,只有到这步才能置空
	*head=p1;
	return head;
}

方法3:从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,最后将第一个节点挪到新表的表尾。

方法1的问题是浪费空间。方法2和方法3效率相当。一般方法2较为常用。

3.逆序遍历单链表

Void ReversList(LIST p)
{
    if(p->next)
       ReversList(p-next);
    visit(p->data);
}O(?)

4.链表有环

1.快慢指针相遇

从头指针开始,每次分别移动2、1个节点

2.每个节点设flag

map<NODE *, int flag> Node;

3.穷举 线性查找到HashSet

每遍历到一个新节点,就用新节点和HashSet集合当中存储的节点作比较,如果发现HashSet当中存在相同节点ID,则说明链表有环,如果HashSet当中不存在相同的节点ID,就把这个新节点ID存入HashSet。

 时间复杂度:HashSet查找为O(1),使得线性查找使得O(N*N)变为O(N*1)

空间复杂度:O(1)变为O(N)

5.环入口

快慢指针法 若无环,快指针先为空

fast = fast->next ? fast->next : NULL; //fast->next == NULL?
if (NULL == fast) break;

https://www.jianshu.com/p/ef71e04241e4

6.单向链表中查找倒数第K个数 两次遍历 ——> 一次遍历

https://www.cnblogs.com/dirkhe/p/6790858.html

p1和p2分别都是head指针,先将p2向右移动k次。(此时k为2)

只需要继续保持p1和p2等间距的右移,当p2的next为null,则证明p1所指的结点的值为倒数第k个节点的值

7.查找单链表的中间节点

快慢指针方法

建立两个指针,一个指针一次遍历两个节点,另一个节点一次遍历一个节点,当快指针遍历到空节点时,慢指针指向的位置为链表的中间位置。

8.两个单链表交点

https://blog.csdn.net/u010983881/article/details/78896293

1.穷举 HashSet两次遍历 时间复杂度为:O(max(len1+len2);空间复杂度O(len1)

2.设flag

3.利用有环链表思路

对于两个没有环的链表相交于一节点,则在这个节点之后的所有结点都是两个链表所共有的。如果它们相交,则最后一个结点一定是共有的,则只需要判断最后一个结点是否相同即可。时间复杂度为O(len1+len2)。

对于相交的第一个结点,则可求出两个链表的长度,然后用长的减去短的得到一个差值 K,然后让长的链表先遍历K个结点。

还可以这样:其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个

9.KMP算法之next数组

next函数:

(1)next[0]= -1,任何串的第一个字符的模式值规定为-1

(2)next[j] = -1,模式串t中下标为j的字符,如果与首字符相同k个字符不等或者相等但t[j] == t[k](匹配夹带了a[j])。1≤k<j

t=”aba” 则 next[2]=-1,因k取1,t[2]与首字母相同,但前1个不匹配

t=”abC abC ad” 则 next[6]=-1,因k取3,但t[3]=t[6]

(3)next[j] = k,模式串t中下标为j的字符,如果k个字符相等,且t[j] != t[k](匹配不能夹带a[j])。1≤k<j

(4)next[j]=0,除(1)(2)(3)的其他情况。

设在字符串S中查找模式串T,若S[m]!=T[n],那么,取T[n]的模式函数值next[n]

(1) next[n]=  -1 表示S[m]T[0]间接比较过了,不相等,下一次比较 S[m+1] T[0]

(2) next[n]=0 表示比较过程中产生了不相等,下一次比较 S[m] T[0]

(3) next[n]= k >0 k<n,表示S[m]的前k个字符与T中的,开始k个字符已经间接比较相等了,下一次比较S[m]T[k]相等吗?

10.两个栈实现一个队列

入队时,直接压入stack1中

出队时,判断stack2是否为空,如果stack2为空,则将stack1中的元素倒入stack2中,否则直接弹出stack2中的元素

//入队操作
void EnQueue(stack<int> &s1,stack<int> &s2,int m)
{
    s1.push(m);
}

//出队操作
void DeQueue(stack<int> &s1,stack<int> &s2,int &m)
{
    if (s2.empty())
    {
        int p = s1.size();
        for (int i=0;i<p;i++)
        {
            s2.push(s1.top());
            s1.pop();
        }    
    }
    m = s2.top();
    s2.pop();
}

11.两个队列实现一个栈

 将queue1用作进栈出栈,queue2作为一个中转站

入栈时,直接压入queue1中

出栈时,先将queue1中的元素除最后一个元素外依次出队列,并压入队列queue2中,将留在queue1中的最后一个元素出队列即为出栈元素,最后还要把queue2中的元素再次压入queue1中

//进栈操作
void stackpush(queue<int> &q1,queue<int> &q2,int m)
{
    q1.push(m);
}

//出栈操作
void stackpop(queue<int> &q1,queue<int> &q2,int &m)
{
    int p = q1.size();
    for (int i=0;i<p-1;i++)
    {
        q2.push(q1.front());
        q1.pop();
    }
    m = q1.front();
    q1.pop();
    int l = q2.size();
    for (int j = 0;j<l;j++)
    {
        q1.push(q2.front());
        q2.pop();
    }
}

12.二叉树的树高与树宽

高度和深度定义https://blog.csdn.net/bwh12398/article/details/78011819

https://blog.csdn.net/K346K346/article/details/51076268

13.根节点到指定节点的路径

https://blog.csdn.net/shixiaoguo90/article/details/23759887

14.两个节点的公共结点

如果结点中有一个指向父结点的指针,我们可以把问题转化为求两个链表的共同结点。

*poj2499

http://www.cnblogs.com/allensun/archive/2010/11/08/1872028.html

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值