单链表逆置
1 | public void reverseNodeList() { |
判断单链表相交
问题a:两链表都是没环的
1 | 问题a: |
问题b:两链表环的情况不知道
先用追逐法判断单链表是否有环1
2判断有环的就是p0和p1都指向头结点,然后每次1走一步,b走两步,看走到的点是不是相同
(可以这么去理解,有n个站台,a每次走一个站台,b每次走两个,如果这是个线性的那么b永远在a前面,如果有环,就是b得往回走,那么a,肯定是会相遇的,会有可能不相遇吗?如果b不是走两步的话,是有可能的,b的步伐太大,正好跳过了相遇点,但是每次走两步,假设跳过去相遇点,那么就应该是相遇点的前一个节点,那么相遇点实际上就有两个方向了,这就与单链表相矛盾了)
3种情形,都没环就是问题a,1个有环1个无环不可能相交,两个都有环还相交,环一定是共有的,即a环的相遇点在b的环上(记住吧)
找出第一个相交点
如果都没环(相交类比成一个Y字型),同样A的尾节点指向b的头结点,转换成用追逐法求环的那个偶遇点问题
剩下两个都有环的情况,
计算出两链表的长度lA、lB,(环的长度和环到入口点长度之和就是链表长度)
如果lA>lB,则链表A指针先走lA-lB,然后链表B指针开始走,两者相遇的点就是相交点
如果lB>lA,则链表B指针先走lB-lA,然后链表A指针开始走,两者相遇的点就是相交点
一、排序
排序分内部排序和外部排序(需不需要访问外存)
排序算法的稳定是值排序后 2 个相等键值的顺序和排序之前它们的顺序相同
1.冒泡排序(n^2,最好n,最差n^2,内部稳定)
1 | //我自己的,理解更合自己的胃口 |
1 | public class BubbleSort implements IArraySort { |
2.选择排序(n^2,,内部不稳定)
1 | public class SelectionSort implements IArraySort { |
3.插入排序(n^2,最好n,最差n^2,内部稳定)
1 | public class InsertSort implements IArraySort { |
4.希尔排序(以插入排序为基础)
1 | public class ShellSort implements IArraySort { |
5.快速排序(分治的思想)
1 | public class QuickSort implements IArraySort { |
6.堆排序
Math.floor(n/2)的位置开始,不断调整堆,调整堆的操作是个递归的操作(例如建造大顶堆设置索引largest=i,将其和子节点三者最大值和i的值进行对调,largest指向原最大值的位置,如果i=largest,则递归结束了(因为堆的下面是有序的了),否则继续递归该节点)
7.归并排序
不断将原序列切分成两个子序列,调用
二、最长子序列和
内容节选自 http://www.cnblogs.com/conw/p/5896155.html
1.O(N^3)的算法
i从1到n,j从i到n,k从i到j算出以i,j为首尾的子序列的和,最大值即为所求。
2.O(N^2)的算法
sum[i]表示从1到i的和,求出sum,从第i个数到第j个数的和即sum[j]-sum[i-1]。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//N是数组长度,num是待计算的数组,sum是数组前缀和,放在全局区是因为可以开很大的数组
int N, num[16384], sum[16384];
int main()
{
//输入数据
scanf("%d", &N);
for(int i = 1; i <= N; i++)
scanf("%d", &num[i]);
//计算数组前缀和
sum[0] = 0;
for(int i = 1; i <= N; i++) {
sum[i] = num[i] + sum[i - 1];
}
int ans = num[1]; //ans保存最大子序列和,初始化为num[1]能保证最终结果正确
//i和j分别是枚举的子序列的起点和终点
for(int i = 1; i <= N; i++) {
for(int j = i; j <= N; j++) {
int s = sum[j] - sum[i - 1];
if(s > ans) ans = s;
}
}
printf("%d\n", ans);
return 0;
}
3.分治O(N*logN)
1 | #include <stdio.h> |
4.动态规划O(N)
我们用dp[n]表示以第n个数结尾的最大连续子序列的和,于是存在以下递推公式:dp[n] = max(0, dp[n-1]) + num[n]
仔细思考后不难发现这个递推公式是正确的,则整个问题的答案是max(dp[m]) | m∈[1, N]。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <stdio.h>
//N是数组长度,num是待计算的数组,放在全局区是因为可以开很大的数组
int N, num[134217728];
int main()
{
//输入数据
scanf("%d", &N);
for(int i = 1; i <= N; i++)
scanf("%d", &num[i]);
num[0] = 0;
int ans = num[1];
for(int i = 1; i <= N; i++) {
if(num[i - 1] > 0) num[i] += num[i - 1];
else num[i] += 0;
if(num[i] > ans) ans = num[i];
}
printf("%d\n", ans);
return 0;
}
没有创建另外的数组我感觉有点混乱…
5.又一个O(N)的算法
。。。