算法题解

1、利用字符重复出现的次数,编写一个方法,实现基本的字符串压缩功能。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<conio.h>
 4 #include <string.h>
 5
 6 /*
 7 重复字符压缩
 8 */
 9 void RepeatCharReduce(char *str, int n, char *s){
10
11 //    char s[20];
12     char tmp = str[0];
13     s[0] = tmp;
14     int j = 1;
15     int count = 1;
16     for(int i = 1; i <n; i++){
17         if(str[i] == tmp){
18             count++;
19         }
20         else{
21             s[j] = count;
22             j++;
23             tmp = str[i];
24             s[j] = str[i];
25             count = 1;
26             j++;
27         }
28     }
29     s[j] = count;
30
31 }
32
33 int main(){
34     char str[] = "aabcccccaaa";
35     char s[20] = "0";
36     RepeatCharReduce(str, 11, s);
37     for(int j = 0; j < 11; j++){
38         printf("%c", str[j]);
39     }
40     printf("\n");
41     for(int i = 0; i < 11; i += 2){
42         printf("%c%d", s[i], s[i+1]);
43     }
44     printf("\n");
45     getch();
46     return 0;
47 }

2、给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符‘a‘和‘b‘移动到字符串的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<conio.h>
 4 #include<math.h>
 5 #include<time.h>
 6 #include <string.h>
 7
 8 void ReverseString(char *s, int from, int to)
 9 {
10     while(from < to){
11     char t = s[from];
12     s[from++] = s[to];
13     s[to--] = t;
14     }
15 }
16
17 void LeftRotateString(char *s, int n, int m)
18 {
19     m %= n;
20     ReverseString(s, 0, m-1);
21     ReverseString(s, m, n-1);
22     ReverseString(s, 0, n-1);
23 }
24
25 int main(){
26     char s[] = "abcdefgh";
27     for(int i = 0; i < 8; i++){
28         printf("%c ", s[i]);
29     }
30     printf("\n");
31     LeftRotateString(s, 8, 3);
32     for(int i = 0; i < 8; i++){
33         printf("%c ", s[i]);
34     }
35     printf("\n");
36     getch();
37     return 0;
38 }

3、链表翻转。给出一个链表和一个数k,比如,链表为1→2→3→4→5→6,k=2,则翻转后2→1→6→5→4→3,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→6→5,用程序实现。

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<conio.h>
  4 #include<math.h>
  5 #include<time.h>
  6 #include <string.h>
  7
  8 #define OK 1
  9 #define ERROR 0
 10 #define TRUE 1
 11 #define FALSE 0
 12
 13 #define MAXSIZE 20 /* 存储空间初始分配量 */
 14
 15 typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
 16 typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */
 17
 18  typedef struct Node{
 19      int data;
 20      struct Node *next;
 21 }Node, *LinkList;
 22
 23 /* 初始化顺序线性表 */
 24 Status InitList(LinkList *L)
 25 {
 26     *L=(LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点 */
 27     if(!(*L)) /* 存储分配失败 */
 28     {
 29         return ERROR;
 30     }
 31     (*L)->next=NULL; /* 指针域为空 */
 32     return OK;
 33 }
 34
 35
 36 /*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
 37 void CreateListHead(LinkList *L, int n)
 38 {
 39     LinkList p;
 40     int i;
 41     srand(time(0));                         /* 初始化随机数种子 */
 42     *L = (LinkList)malloc(sizeof(Node));
 43     (*L)->next = NULL;                      /*  先建立一个带头结点的单链表 */
 44     for (i=0; i < n; i++)
 45     {
 46         p = (LinkList)malloc(sizeof(Node)); /*  生成新结点 */
 47         p->data = rand()%100+1; /*  随机生成100以内的数字 */
 48         printf("%d ", p->data);
 49         p->next = (*L)->next;
 50         (*L)->next = p;                      /*  插入到表头 */
 51     }
 52 }
 53 /* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
 54 int ListLength(LinkList L)
 55 {
 56     int i=0;
 57     LinkList p=L->next; /* p指向第一个结点 */
 58     while(p)
 59     {
 60         i++;
 61         p=p->next;
 62     }
 63     return i;
 64 }
 65 Status visit(ElemType c)
 66 {
 67     printf("-> %d ",c);
 68     return OK;
 69 }
 70 /* 初始条件:顺序线性表L已存在 */
 71 /* 操作结果:依次对L的每个数据元素输出 */
 72 Status ListTraverse(LinkList L)
 73 {
 74     LinkList p=L->next;
 75     while(p)
 76     {
 77         visit(p->data);
 78         p=p->next;
 79     }
 80     printf("\n");
 81     return OK;
 82 }
 83
 84 LinkList ListReverse2(LinkList L)
 85 {
 86     LinkList current, p;
 87     if (L == NULL)
 88     {
 89         return NULL;
 90     }
 91     current = L->next;
 92     while (current->next != NULL)
 93     {
 94         p = current->next;
 95         current->next = p->next;
 96         p->next = L->next;
 97         L->next = p;
 98     }
 99     ListTraverse(L);
100     return L;
101 }
102 /*
103 1、链表翻转。给出一个链表和一个数k,
104 比如,链表为1→2→3→4→5→6,k=2,则翻转后2→1→6→5→4→3,
105 若k=3,翻转后3→2→1→6→5→4,
106 若k=4,翻转后4→3→2→1→6→5,用程序实现。
107
108 对于链表而言只是对指针的指向调换,所以不会耗费额外存储空间,空间复杂度O(1)
109 时间复杂度此处看来也是线性的
110 */
111
112 LinkList ReverseSpecArea(LinkList L, int k){
113     LinkList current, p, q;
114     LinkList temp;
115     int i = 1;
116     if (L == NULL)
117     {
118         return NULL;
119     }
120     current = L->next;
121
122     while (current->next != NULL)
123     {
124         p = current->next;
125         current->next = p->next;
126         p->next = L->next;
127         L->next = p;
128         if(++i >= k){
129             break;
130         }
131     }//current始终指向起先除去头结点的第一个元素
132     temp = current;
133     current = current->next;
134     while(current->next != NULL){
135         p = current->next;
136         current->next = p->next;
137         p->next = temp->next;
138         temp->next = p;
139     }
140     ListTraverse(L);
141
142     return L;
143 }
144
145
146 void ReverseString(char *s, int from, int to)
147 {
148     while(from < to){
149     char t = s[from];
150     s[from++] = s[to];
151     s[to--] = t;
152     }
153 }
154
155 void LeftRotateString(char *s, int n, int k)
156 {
157     k %= n;
158     ReverseString(s, 0, k-1);
159     ReverseString(s, k, n-1);
160 }
161
162 int main(){
163     LinkList L;
164     LinkList h;
165     Status i;
166     int j,k,pos,value;
167     int length;
168     char opp;
169     ElemType e;
170     i=InitList(&L);
171     printf("%d\n", i);
172
173     CreateListHead(&L,10);
174     printf("\n");
175     length = ListLength(L);
176     printf("%d\n", length);
177     printf("整体创建L的元素(头插法):\n");
178     ListTraverse(L);
179     printf("\n");
180     h = L->next;
181     while(h){
182         printf("%d ", h->data);
183         h = h->next;
184     }
185     printf("\n");
186     ListReverse2(L);
187 //    printf("反转指定位置3的元素\n");
188 //    ReverseSpecArea(L, 3);
189     printf("反转指定位置5的元素\n");
190     ReverseSpecArea(L, 5);
191
192     getch();
193     return 0;
194 }

时间: 2024-10-10 23:03:35

算法题解的相关文章

POJ 3259 Wormholes SPFA算法题解

本题其实也可以使用SPFA算法来求解的,不过就一个关键点,就是当某个顶点入列的次数超过所有顶点的总数的时候,就可以判断是有负环出现了. SPFA原来也是可以处理负环的. 不过SPFA这种处理负环的方法自然比一般的Bellman Ford算法要慢点了. #include <stdio.h> #include <string.h> #include <limits.h> const int MAX_N = 501; const int MAX_M = 2501; const

POJ 3461 Oulipo KMP算法题解

本题就是给出很多对字符串,然后问一个字符串在另外一个字符串出现的次数. 就是所谓的Strstr函数啦. Leetcode有这道几乎一模一样的题目. 使用KMP算法加速,算法高手必会的算法了. 另外看见讨论说什么使用KMP还超时,最大可能是没有真正理解next table的含义,写了错误的代码,故此虽然自己运行结果正确,但是却没有真正发挥next table的作用,使得算法退化为暴力法了,所以运行正确,但超时. KMP参考: http://blog.csdn.net/kenden23/articl

POJ 2560 Freckles Prime算法题解

本题是求最小生成树. 给出的是坐标节点,然后需要根据这些坐标计算出各个点之间的距离. 除此就是标准的Prime算法了,能使用Prime的基本上都可以使用Kruskal. 这些经典的算法一定要多写,熟练掌握,否则很难灵活运用的. 而且经典的算法之所以为经典,原因之一是没那么容易自己凭空想象出来的,所以要熟练. #include <stdio.h> #include <string.h> #include <queue> #include <float.h> #

POJ 2553 The Bottom of a Graph TarJan算法题解

本题分两步: 1 使用Tarjan算法求所有最大子强连通图,并且标志出来 2 然后遍历这些节点看是否有出射的边,没有的顶点所在的子强连通图的所有点,都是解集. Tarjan算法就是模板算法了. 这里使用一个数组和一个标识号,就可以记录这个顶点是属于哪个子强连通图的了. 然后使用DFS递归搜索所有点及其边,如果有边的另一个顶点不属于本子强连通图,那么就说明有出射的边. 有难度的题目: #include <stdio.h> #include <stdlib.h> #include &l

POJ 2914 Minimum Cut 最小割算法题解

最标准的最小割算法应用题目. 核心思想就是缩边:先缩小最大的边,然后缩小次大的边,依此缩小 基础算法:Prime最小生成树算法 不过本题测试的数据好像怪怪的,同样的算法时间运行会差别很大,而且一样的代码替换,居然会WA.系统出错的几率很小,难倒测试系统本题会有错误? 懒得继续测试这道题的系统了,反正算法正确,AC. #include <stdio.h> #include <string.h> #include <limits.h> const int MAX_N = 5

POJ 3974 Palindrome Manacher算法题解

本题就是求最长的回文子串. 字符串超长,不过限时却是也很长的15秒,最长的限时之一题目了,如果限时短点的话,估计能过的人不多. 使用Mancher算法是可以秒杀的. 模板式的Manacher算法: #include <stdio.h> #include <vector> #include <string.h> #include <algorithm> #include <iostream> #include <string> #inc

HDU 2255 奔小康赚大钱 KM算法题解

KM算法求的是完备匹配下的最大权匹配,是Hungary算法的进一步,由于Hungary算法是最大匹配的算法,不带权. 经典算法,想不出来的了,要參考别人的.然后消化吸收吧. 由于真的非常复杂的算法. 我理解算法匹配思想: 1 開始的时候,全部边都记录自己的最优匹配,无论有没有冲突 2 递归循环的时候.假设找不到自己的最优匹配,那么就找次要匹配 3 次要匹配不行,继续找下一个次优匹配,全部点都一定要找到解 难点: 怎样记录这些信息,以便循环处理全部点. 牵涉到非常多什么增广路,交错树之类的,名词,

算法题解之math类题

Count Primes 质数计数 思路1:暴力法.其中判断每一个数n是不是质数需要验证是否任何小于n的数都不能整除n,这一步是O(n).因此整体复杂度是O(n^2). 思路2:思路1的优化版.如果一个数n不是质数,则n = p * q.令 p <= q,则可以推出 p * p <= n,即 p <= √n.因此思路一中只需要判断是否任何小于等于√n都不能整除n.整体时间复杂度变为O(n^1.5). 1 public int countPrimes(int n) { 2 int coun

LeetCode算法题解

1.给定两个正整数(二进制形式表示)A和B,问把A变为B需要改变多少位(bit)?也就是说,整数A和B的二进制表示中有多少位是不同的?(181) 解法一:举例说明,为了减少复杂度,就使用八位二进制吧.设 A = 0010 1011, B = 0110 0101.1. C = A & B = 0010 0001:2. D = A | B = 0110 1111:3. E = C ^ D = 0100 1110:4. 结果E中有4个1,那么也就是说将A变成B,需要改变4位(bit).至于如何判断E的

算法题解之滑动窗口

Substring with Concatenation of All Words 寻找所有词连接的子串 思路:由于该字串是所有词典中的词连接的,所以该字串长度固定.因此本题可以看作一个滑动窗口的题.为了去除重复工作,每次滑动一个单词的长度,因此起始位置就有n种(n为单词长度).每种起始位置的滑动策略如下: 如果当前窗口满足条件,则窗口只往后移动一个单词,并且下一次只检查最后一个单词(中间的单词肯定满足条件).    如果当前窗口不满足条件,则有两种情况: 1.当前窗口内不满足条件的第一个单词不