当前位置:   article > 正文

打卡leetcode第14天_给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 nee

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符

1.实现strStr(三种解法)

【题目】

实现 strStr() 函数。

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。

说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。

【分析】

法1:暴力解法:

我们可以让字符串 needle 与字符串 haystack 的所有长度为 m 的子串均匹配一次。

为了减少不必要的匹配,我们每次匹配失败即立刻停止当前子串的匹配,对下一个子串继续匹配。如果当前子串匹配成功,我们返回当前子串的开始位置即可。如果所有子串都匹配失败,则返回 −1。

【C】

  1. int strStr(char * haystack, char * needle){
  2. for(int i=0;i+strlen(needle)<=strlen(haystack);i++){
  3. bool flag=true;
  4. for(int j=0;j<strlen(needle);j++){
  5. if(haystack[i+j]!=needle[j]){
  6. flag=false;
  7. break;
  8. }
  9. }
  10. if(flag){
  11. return i;
  12. }
  13. }
  14. return -1;

【C++】

枚举原串 ss 中的每个字符作为「发起点」,每次从原串的「发起点」和匹配串的「首位」开始尝试匹配:

    匹配成功:返回本次匹配的原串「发起点」。
    匹配失败:枚举原串的下一个「发起点」,重新尝试匹配。

  1. class Solution {
  2. public:
  3. int strStr(string s, string p) {
  4. int n = s.size(), m = p.size();
  5. for(int i = 0; i <= n - m; i++){
  6. int j = i, k = 0;
  7. while(k < m and s[j] == p[k]){
  8. j++;
  9. k++;
  10. }
  11. if(k == m) return i;
  12. }
  13. return -1;
  14. }
  15. };

都很慢

法2:直接用strStr()返回第一个符合的位置,再减去第一个长字符串

【C】

  1. int strStr(char * haystack, char * needle){
  2. if (needle==0)
  3. return 0;
  4. int ans=strstr(haystack,needle)-haystack;
  5. if (ans<0)
  6. return -1;
  7. else
  8. return ans;
  9. }

这种很快 ,比后边kmp算法还快

法3:KMP算法,求next数组,详细解答见代码随想录

【C】

  1. 前缀表不减一版本
  2. void getNext(int* next, char* s) {
  3. //初始化 next
  4. int j = 0;
  5. next[0] = j;
  6. for (int i = 1; i < strlen(s); i++) { //注意 i 从 1 开始
  7. //若前后缀不相同
  8. while (j > 0 && s[i] != s[j]) {
  9. //则向前回退
  10. j = next[j - 1];
  11. }
  12. //若前后缀相同
  13. if (s[i] == s[j]) {
  14. //i 和 j 同时向后移动(i 的增加在 for 循环里)
  15. j++;
  16. }
  17. //将 j(前缀的长度)赋值给 next[i]
  18. next[i] = j;
  19. }
  20. }
  21. int strStr(char * haystack, char * needle){
  22. int len1 = strlen(haystack);
  23. int len2 = strlen(needle);
  24. //当 needle 为空字符串时,返回 0
  25. if (len2 == 0) {
  26. return 0;
  27. }
  28. //构建 next 数组
  29. int* next = malloc(sizeof(int) * len2);
  30. getNext(next, needle);
  31. //next 记录的起始位置为 0,所以这里也从 0 开始
  32. int j = 0;
  33. for (int i = 0; i < len1; i++) { //注意匹配时 i 从 0 开始
  34. //若不匹配
  35. while (j > 0 && haystack[i] != needle[j]) {
  36. //j 退回到之前匹配的位置
  37. j = next[j - 1];
  38. }
  39. //若匹配
  40. if (haystack[i] == needle[j]) {
  41. //i 和 j 同时向后移动(i 的增加在 for 循环里)
  42. j++;
  43. }
  44. //当 j 等于 needle 的长度时,说明字符串 haystack 里出现了字符串 needle
  45. if (j == len2) {
  46. //返回 needle 字符串出现的第一个位置
  47. return (i - len2 + 1);
  48. }
  49. }
  50. //若未找到则说明不存在,返回 -1
  51. return -1;
  52. }

 

 2.通过删除字母匹配到字典中的最长单词

【题目】

【分析】快排再比较

  1. int cmp(const void* a, const void* b){
  2. char* ap = *(char**)a;
  3. char* bp = *(char**)b;
  4. if(strlen(ap) != strlen(bp)){
  5. return strlen(bp) - strlen(ap);
  6. }
  7. return strcmp(ap, bp);
  8. }
  9. bool canDelete(char * s, char * d){
  10. int sLen = strlen(s);
  11. int dLen = strlen(d);
  12. int i = 0, j = 0;
  13. while(i < sLen && j < dLen){
  14. if(s[i] == d[j]){
  15. j++;
  16. if(j == dLen){
  17. return true;
  18. }
  19. }
  20. i++;
  21. }
  22. return false;
  23. }
  24. char * findLongestWord(char * s, char ** dictionary, int dictionarySize){
  25. qsort(dictionary, dictionarySize, sizeof(char*), cmp);
  26. int sLen = strlen(s);
  27. int i, j, flag = 0;
  28. char* ans = malloc(sizeof(char) * (sLen + 1));
  29. for(i = 0; i < dictionarySize; i++){
  30. if(canDelete(s, dictionary[i]) && sLen >= strlen(dictionary[i])){
  31. strcpy(ans, dictionary[i]);
  32. flag = 1;
  33. break;
  34. }
  35. }
  36. if(flag == 0){
  37. ans = "";
  38. }
  39. return ans;
  40. }

3.有序数组的平方

【题目】

【分析】

法1:先算平方再快排

  1. int cmp(const void* a,const void* b){
  2. return (*(int*)a-*(int*)b);
  3. }
  4. int* sortedSquares(int* nums, int numsSize, int* returnSize){
  5. int *ans=(int*)malloc(sizeof(int)*numsSize);
  6. for(int i=0;i<numsSize;i++){
  7. ans[i]=nums[i]*nums[i];
  8. }
  9. qsort(ans,numsSize,sizeof(int),cmp);
  10. *returnSize=numsSize;
  11. return ans;
  12. }

法2:双指针法

  1. --直接平方再两边双指针--
  2. int* sortedSquares(int* nums, int numsSize, int* returnSize) {
  3. int* ans = malloc(sizeof(int) * numsSize);
  4. *returnSize = numsSize;
  5. for (int i = 0, j = numsSize - 1, pos = numsSize - 1; i <= j;) {
  6. if (nums[i] * nums[i] > nums[j] * nums[j]) {
  7. ans[pos] = nums[i] * nums[i];
  8. ++i;
  9. } else {
  10. ans[pos] = nums[j] * nums[j];
  11. --j;
  12. }
  13. --pos;
  14. }
  15. return ans;
  16. }
  17. --第二种--
  18. int* sortedSquares(int* nums, int numsSize, int* returnSize){
  19. int *reNums;
  20. int left = 0,right = numsSize - 1,i = numsSize - 1;//定义左右“指针”分别从最左和最右开始
  21. reNums = malloc(sizeof(int) * numsSize); //申请动态数组将原来的值计算比较赋值给新的数组即reNums
  22. for(int j = 0; j < numsSize; j++){ // 遍历整个数组计算各个数的平方值并重新赋值给nums
  23. nums[j] = pow(nums[j],2);
  24. }
  25. while(left <= right){ // 当右边大于等于左边时进入循环
  26. if(nums[right] >= nums[left]){//最后一次肯定是左边右边遍历到同一个位置所以等于也要判断
  27. reNums[i] = nums[right--];//右边赋值后像左偏移-1
  28. }
  29. else{
  30. reNums[i] = nums[left++];//左边赋值后向右偏移即+1
  31. }
  32. i--;
  33. }
  34. *returnSize = numsSize;//返回数组大小和传入的大小一致
  35. return reNums;
  36. }

4.移动0

【题目】

【分析】

法1:循环遍历法:

  1. void moveZeroes(int* nums, int numsSize){
  2. /* 方法一:先统计所有非零数、然后放到数组前端,剩余空间全补0 */
  3. int j = 0;
  4. for (int i = 0; i <= numsSize -1; i++) {
  5. //1步:找到非零数放在数组前端
  6. if (nums[i] != 0) {
  7. nums[j] = nums[i];
  8. j++;
  9. }
  10. }
  11. //2步:从j开始到数组末端全赋值0(j之前都是非0数)
  12. while (j <= numsSize-1) {
  13. nums[j++] = 0;
  14. }
  15. }

法2:双指针法:参考:https://leetcode-cn.com/problems/move-zeroes/solution/cyu-yan-ti-jie-xun-huan-bian-li-fa-by-ma-3xgu/

/*
    方法二:双指针交换法(该题的本质是考察双指针,i 代表右指针,j代表左指针)
    0  1  0  3  12
    i
    j

    0  1  0  3  12     i指向数组第1个非零数,准备交换nums[i]和nums[j],即准备交换1和0
       i
    j

    1  0  0  3  12
       i               swap(&nums[i], &nums[j])交换,即1和0交换完成(第1轮交换)
    j

    1  0  0  3  12
             i         i移动到下一个非0数字,j向前移动1步,准备交换nums[i]和nums[j],即准备交换3和0
       j

    1  3  0  0  12
             i         swap(&nums[i], &nums[j])交换,即3和0交换完成(第2轮交换)
       j

    1  3  0  0  12
                 i     i移动到下一个非0数字(刚好是数组结尾),j向前移动1步,准备交换nums[i]和nums[j],即准备交换12和0
          j

    1  3  12  0  0
                 i     swap(&nums[i], &nums[j])交换,即12和0交换完成(第3轮交换)。由于i已经到达数组结尾,因此结束。
           j
*/

  1. void swap(int *a, int *b) {
  2. int t = *a;
  3. *a = *b;
  4. *b = t;
  5. }
  6. void moveZeroes(int* nums, int numsSize) {
  7. // 方法二:双指针交换法(i为右指针, j为左指针)
  8. int j = 0;
  9. for (int i = 0; i <= numsSize -1; i++) {
  10. if (nums[i] != 0) {
  11. swap(&nums[i], &nums[j]); // 交换数组下标索引i和j对应的元素值
  12. j++; // 左指针右移1
  13. }
  14. }
  15. }

5.反转字符串

【题目】

【分析】

双指针法:

【C】

  1. void swap(char *a, char *b) {
  2. char t = *a;
  3. *a = *b, *b = t;
  4. }
  5. void reverseString(char *s, int sSize) {
  6. for (int left = 0, right = sSize - 1; left < right; ++left, --right) {
  7. swap(s + left, s + right);
  8. }
  9. }

【C++】

reverse()

  1. class Solution {
  2. public:
  3. void reverseString(vector<char>& s) {
  4. reverse(s.begin(),s.end());
  5. }
  6. };

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/50670
推荐阅读
相关标签
  

闽ICP备14008679号