双指针的魅力

转载 2015年07月10日 00:07:08

转载:http://blog.csdn.net/zzran/article/details/8456721


在解决问题过程中,经常碰到使用双指针解决的情况,使用双指针,可以很高效很快速的解决问题,罗列一下应用双指针的情况:

1,将给定的英文字符串进行反转,例如: I love programming。得到的结果是:.gnimmargorp evol I。下面给出核心代码:

  1. #include<stdio.h>  
  2. #include<string.h>  
  3.   
  4. void swap_string(char *p_start, char *p_end) {  
  5.     char temp;  
  6.     while(p_start <= p_end) {  
  7.         temp = *p_start;  
  8.         *p_start = *p_end;  
  9.         *p_end = temp;  
  10.         p_start++;  
  11.         p_end--;  
  12.     }  
  13. }  
  14.   
  15. void main() {  
  16.     char str[] = "I love programming.";  
  17.     swap_string(str, str + strlen(str) - 1);  
  18.     printf("%s\n", str);  
  19. }  

2,给定一个字符串,例如:"   test **   ",要求出去字母之外其他多余的字符,这也需要设定两个指针,一个慢指针和一个快指针,核心代码如下:

  1. #include<stdio.h>  
  2. #include<string.h>  
  3.   
  4. void trim_word(char *word) {  
  5.     char *p_slow = word;  
  6.     char *p_fast = word;  
  7.     while(*p_fast) {  
  8.         if(!(*p_fast >= 'a' && *p_fast <= 'z') && !(*p_fast >= 'A' && *p_fast <= 'Z')) {  
  9.             p_fast++;  
  10.         } else {  
  11.             *p_slow++ = *p_fast++;  
  12.         }  
  13.     }  
  14.     *p_slow = '\0';  
  15. }  
  16. void main() {  
  17.     char word[] = "   test **   ";  
  18.     trim_word(word);  
  19.     printf("%s\n", word);  
  20. }  
如果给定的字符串是这样的:" test***ing ",这个算法也可以胜任的。

3,给定一个字符串,例如:"abccba",判断它是否是回文。可以应用数组解决,但是数组的索引速度没有指针的移动速度快,所以设定两个指针,一个指向字符串开始,一个指向字符串结尾,同步移动。核心代码如下:

  1. #include<stdio.h>  
  2. #include<string.h>  
  3.   
  4. int is_palindrome(char *str) {  
  5.     char *p_start = str;  
  6.     char *p_end = str + strlen(word) - 1;  
  7.     while(p_start < p_end) {  
  8.         if(*p_start != *p_end) {  
  9.             return 0;  
  10.         }  
  11.         p_start++;  
  12.         p_end--;  
  13.     }  
  14.     return 1;  
  15. }  
  16. void main() {  
  17.     char string[] = "abccba";  
  18.     if(is_palindrome(string)) {  
  19.         printf("string is palindrome.\n");  
  20.     } else {  
  21.         printf("string is not palindrome.\n");  
  22.     }  
  23. }  

4,判断一个单链表是否有环,可以设置两个指针,一个指针每次移动一步,另一个指针每次移动两步,如果存在环的话,移动快的指针一定可以追上移动慢的指针。如下代码没有在真实的环境中跑过,只是一个基本的思路:

  1. int is_cycling(LinkList L) {  
  2.     LinkNode *p_slow = L;  
  3.     LinkNode *p_fast = L;  
  4.     while(p_fast && p_fast->next) {  
  5.         p_fast = p_fast->next;  
  6.         p_fast = p_fast->next;  
  7.         p_slow = p_slow->next;  
  8.         if(p_slow == p_fast) {  
  9.             return 1;  
  10.         }  
  11.     }  
  12.     return 0;  
  13. }  

5,给定一个链表,首先假设链表正向数或者反向数的第一个的标号都为1,不要受数组的影响。要求是找到链表中倒数第k个节点。链表的缺点之一就是不能像数组一样进行随机的存储和读取。比较笨拙的办法就是先遍历一遍链表,求出它的长度n,因为是找倒数第k个,所以我们只要找到整数第n-k个就可以了。另外一种比较巧妙的方法就是设定两个指针,一个指针先移动k-1步,那么它指向的就是链表中的第k个节点,然后再设置一个指针,指向链表头,假设头部中存储数据。那么两个指针同时移动,直至第一个指针指向空为止。核心代码如下,需要注意k的值超过链表长度的情况,同时,代码也只是基本思路,为经过验证:

  1. LinkNode get_node(LinkList L, int k) {  
  2.     LinkNode *p_first = L;  
  3.     LinkNode *p_second = L;  
  4.     int i = 0;  
  5.     while(i < k) {  
  6.         p_first = p_first->next;  
  7.         i++;  
  8.     }  
  9.   
  10.     if(p_first == NULL)  
  11.         return NULL;  
  12.   
  13.     while(p_first != NULL) {  
  14.         p_first = p_first->next;  
  15.         p_second = p_second->next;  
  16.     }  
  17.     return p_second;  
  18. }  

6,给定一个有序数组,然后给定一个数字m,在数组中找出两个数,使得这两个数的和与m相等。这个题目在双指针面前显得轻而易举:

  1. #include<stdio.h>    
  2. #include<stdlib.h>   
  3.   
  4. void FindTwoNumbers(int a[], int n, int dest)  {    
  5.     int *e, *f;    
  6.     e = a;    
  7.     f = a + n - 1;    
  8.     int sum;    
  9.     sum = *e + *f;    
  10.     while(sum != dest && e < f)    
  11.     {    
  12.         if(sum < dest) {    
  13.             sum = sum - *e + *(++e);   
  14.         } else {     
  15.             sum = sum - *f + *(--f);  
  16.         }  
  17.     }    
  18.     if(sum == dest) {    
  19.         printf("%d=%d+%d\n",dest,*e,*f);  
  20.     } else {  
  21.         printf("not find\n");  
  22.     }  
  23. }    
  24.   
  25. void main()    
  26. {     
  27.     int num[] = {1, 2, 4, 7, 11, 15};    
  28.     int temp = 9;    
  29.     FindTwoNumbers(num, sizeof(num)/sizeof(int), temp);    
  30. }    

7,就是字符串移位问题,这个也用到的双指针,假设给定字符串“abcdefg”,让字符串向做移动三位,得到的结果是:“defgabc”,这个怎么做呢,首先找到分界点,将字符串分为两部分,很自然的分界点应该和移动位数有关,故将字符串分为:abc,defg两部分,先分别将两部分翻转成:cbagfed,然后再将整个字符串翻转:defgabc。


8,新增加的这个在严格意义上不能算作双指针,但是也是类似于双指针,给出题目要求:一个数组,有正数和负数,怎么才能求出这个数组中最小绝对值。数组中有正数和负数,同样,设定两个标示,一个指向正数的positive,一个指向负数的negative,positive用来记录正数中最小的元素,negative用来记录负数中最大的元素,想一想,为什么要记录最大的负数,而不是最小的负数,画一个数轴就知道了。最后比较negative和positive的绝对值,返回最小的那个。

  1. #include<iostream>  
  2. using namespace std;  
  3. #define MAX 1000  
  4. int get_min_abs_value(int *a, int n) {  
  5.     int min_positive = MAX;  
  6.     int max_negative = -MAX;  
  7.     int i;  
  8.     int min_abs_value;  
  9.     if(a == NULL || n == 0) {  
  10.         return -1;  
  11.     }  
  12.     for(i = 0; i < n; i++) {  
  13.         if(a[i] < 0) {  
  14.             if(a[i] > max_negative) {  
  15.                 max_negative = a[i];  
  16.             }  
  17.         } else {  
  18.             if(a[i] < min_positive) {  
  19.                 min_positive = a[i];  
  20.             }  
  21.         }  
  22.     }  
  23.     if(min_positive < (-1 * max_negative)) {  
  24.         min_abs_value = min_positive;  
  25.     } else {  
  26.         min_abs_value = -1 * max_negative;  
  27.     }  
  28.     return min_abs_value;  
  29. }  
  30.   
  31. void main() {  
  32.     int a[] = {-9, -31, -4, 5, 8, 10, 32};  
  33.     int n = sizeof(a) / sizeof(int);  
  34.     cout << get_min_abs_value(a, n) << endl;  
  35. }  

9,输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”They are students.”和"aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.”。这个题的思路其实也可以用双指针来完成。首先我们还得设定一个hash表,来记录在第二个字符串中有哪些字母出现。当hash值等于1的时候表示在第二个字符串,也就是要除去的字符串中出现,等于0的时候表示不出现。然后遍历第一个字符串,设定两个指针,一个p_slow, 一个p_fast,如果某个单词的hash值为1,说明要从原始字符串中除去这个单词,那么p_fast++。这个讲解起来有点不清晰,直接给出代码吧。

  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<string.h>  
  4.   
  5. void trim_string(char *string, char *trim_str) {  
  6.     int hash[256] = {0};  
  7.     int len_trim = strlen(trim_str);  
  8.     char *p_slow = string;  
  9.     char *p_fast = string;  
  10.     int i;  
  11.     for(i = 0; i < len_trim; i++) {  
  12.         hash[trim_str[i]]++;  
  13.     }  
  14.     while(*p_fast) {  
  15.         if(hash[*p_fast] > 0) {  
  16.             p_fast++;  
  17.         } else {  
  18.             *p_slow++ = *p_fast++;  
  19.         }  
  20.     }  
  21.     *p_slow = '\0';  
  22. }  
  23.   
  24. void main() {  
  25.     char string[] = "They are students.";  
  26.     char trim[] = "aeiou";  
  27.     trim_string(string, trim);  
  28.     printf("%s\n", string);  
  29. }  

10, remove duplicated characters in a string in O(n) times without using hash. And, I choose to use magic bit:

  1. #include<stdio.h>  
  2. #include<string.h>  
  3.   
  4. void remove_duplicate(char *str) {// assume all characters are little   
  5.     char *p_slow = str;  
  6.     char *p_fast = str;  
  7.     int flag = 0;  
  8.     int value;  
  9.     int bits;  
  10.     while(*p_fast) {  
  11.         value = 1;  
  12.         bits = *p_fast - 'a';  
  13.         value = (value << bits);  
  14.         if((flag & value) == value) {  
  15.             p_fast++;  
  16.         } else {  
  17.             *p_slow++ = *p_fast++;  
  18.             flag |= value;  
  19.         }  
  20.     }  
  21.     *p_slow = '\0';  
  22. }  
  23.   
  24. void main() {  
  25.     char str[] = "abcddbcdefghijm";  
  26.     remove_duplicate(str);  
  27.     printf("%s\n", str);  
  28.     getchar();  
  29. }  


11, 反转句子中单词的顺序,即把一个英文句子的单词顺序倒转,忽略标点符号的处理,例如: I love linux programming. 操作之后结果: .programming linux love I。也需要设定双指针,这个情况和题目1有相似之处,但是又不完全的相同,需要在反转的过程中做一些判断,下面给出代码:

  1. #include<stdio.h>  
  2. #include<string.h>  
  3. void swap_block(char *start, char *end) {  
  4.     char temp;  
  5.     while(start < end) {  
  6.         temp = *start;  
  7.         *start = *end;  
  8.         *end = temp;  
  9.         start++;   
  10.         end--;  
  11.     }  
  12. }  
  13.   
  14. void reverse_sentence(char *str) {  
  15.     char *p_slow = NULL;  
  16.     char *p_fast = NULL;  
  17.     swap_block(str, str + strlen(str) - 1);  
  18.     p_slow = str;  
  19.     p_fast = str;  
  20.     while(*p_fast) {  
  21.         if((*p_fast >= 'a' && *p_fast <= 'z') || (*p_fast >= 'A' && *p_fast <= 'Z')) {  
  22.             p_fast++;  
  23.         } else {  
  24.             swap_block(p_slow, p_fast - 1);  
  25.             while(!(*p_fast >= 'a' && *p_fast <= 'z') && !(*p_fast >= 'A' && *p_fast <= 'Z')) {  
  26.                 p_fast++;//跳过多余的空格  
  27.             }  
  28.             p_slow = p_fast;  
  29.         }  
  30.     }  
  31. }  
  32.   
  33. void main() {  
  34.     char str[] = "I love linux programming.";  
  35.     reverse_sentence(str);  
  36.     printf("%s\n", str);  
  37.     getchar();  
  38. }  


12,给定一个链表,怎么在线性时间内判断是回文。http://blog.csdn.net/zzran/article/details/8510301

版权声明:本文为博主原创文章,未经博主允许不得转载。

C++之经典算法-双指针的魅力

原文:http://blog.csdn.net/zzran/article/details/8456721 拿来主义~ 在解决问题过程中,经常碰到使用双指针解决的情况,使用双指针,可以很高效...

指针的魅力 (已修正)[转载]

序 指针说:love me,love me! 但是他对指针说:I hate u,I hate u! ……   。说起工具不得不让我想起一样东西——锄头,因为原人类有了锄头...

指针的魅力(来自CSDN博客)

指针的魅力 序 指针说:love me,love me! 但是他对指针说:I hate u,I hate u! ……   指针仅仅是作为指针,我们可...

从反转字符串中看指针魅力

 从反转字符串中看指针魅力                                     从开学到现在半个学期过去了(╯‵□′)╯︵┻━┻,我们C语言的学习也进入了一个“学到了指针...

指针的魅力

指针的魅力 序 指针说:love me,love me! 但是他对指针说:I hate u,I hate u! ……   指针仅仅是作为指针,我们可以把它当做有用的工具,为我们...

指针的魅力-----指针数组与数组指针

指针作为C语言一种强大的工具,给程序员带来相当大的便利。然而获得便利的前提是掌握它的使用。对于我这种很肤浅的程序员而言,各种指针的区别很容易让人迷糊,今天发个博,记录一下自己对指针数组与数组指针的理解...
  • LayCui
  • LayCui
  • 2015年07月27日 16:58
  • 187

java 魅力时钟

  • 2012年03月10日 12:47
  • 5KB
  • 下载

形象全面的介绍GIS之魅力

  • 2016年05月05日 15:44
  • 12.24MB
  • 下载

体验魅力 Cognos BI 10 系列,第 2 部分: 制作第一张交互式离线报表

什么是交互式离线报表 IBM Cognos Active Report 是可以与用户交互的离线报表,包含了数据和展现内容,它在无法访问企业内部网络和数据库的情况下仍然可以通过此类报表分析数据,获得有...
  • thy822
  • thy822
  • 2012年05月28日 10:27
  • 2074
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:双指针的魅力
举报原因:
原因补充:

(最多只允许输入30个字)