Leetcode 5.最长回文子串和Leetcode 704.二分查找的C语言题解



Leetcode 5.最长回文子串

题目描述

给你一个字符串 s,找到 s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

C语言代码

char* longestPalindrome(char* s) {
    int i, j, max = 0, re = 0;
    int len = strlen(s);
    for (i = 1; i < len; i++)//奇数回文
    {
        int left = i - 1;
        int right = i + 1;
        while(left >= 0 && right < len && s[left] == s[right])
        {
            left--;
            right++;
        }
        if(max < (right - left - 1))
        {
            max = right - left - 1;
            re = left + 1;
        }
    }
    for(i = 1; i < len; i++)//偶数回文
    {
        int left = i-1;
        int right = i;
        while(left >= 0 && right < len && s[left] == s[right])
        {
            left--;
            right++;
        }
        if(max < (right - left - 1))
        {
            max = right - left - 1;
            re = left + 1;
        }
    }
    if(max < 2)
    {
        s[1] = '\0';
        return s;
    }
    s[re + max] = '\0';
    return s + re;
}

思路解释

回文数列有奇数回文和偶数回文,所以我分两个循环分别进行寻找。

第一个for循环是奇数回文的查找,从下标 1 开始循环(因为left需要分布在下标 i 的左边),让left和right分别分布在下标 i 的左右,然后进入循环,判断left和right下标所代表的字符是否相同,并且left和right的下标是否超出整个字符串的范围(0 ~ len),以此决定是否结束循环。结束循环后,将left - right - 1的结果与容纳最长回文字符串长度的变量max的值比较,取最大值,变量re记录最长回文字符串的左下标left - 1。

偶数回文同上。

最后执行判断,如果max的值小于 2 ,返回字符串首字符;否则返回最长回文字符串。

Leetcode 704.二分查找

题目描述

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:

  1. 你可以假设 nums 中的所有元素是不重复的。
  2. n 将在 [1, 10000]之间。
  3. nums 的每个元素都将在 [-9999, 9999] 之间。

C语言代码

int search(int* nums, int numsSize, int target) {
    int left = 0;
    int right = numsSize - 1;
    while(left <= right)
    {
        int mid = (left + right) / 2;
        if(nums[mid] > target)
        {
            right = mid - 1;
        }
        else if(nums[mid] < target)
        {
            left = mid+1;
        }
        else
        {
            return mid;
        }
    }
    return -1;
}

解题思路

因为数组元素有序(升序),且没有重复元素,这道题适合用二分查找。

判断 left 是否不大于 right ,以此决定是否进入循环,mid 取 left 和 right 的中位数,判断数组该下标的值与 target 的关系,如果等于 target ,直接返回 mid ;如果小于 target ,left 移动至 mid 右边一位;如果大于 target ,right 移动至 mid 左一位。

当循环结束时还没有返回任何的值,则返回 -1 ,说明数组nums不存在与 target 相等的元素。

二分查找感悟

二分法查找在左右闭合区间和左闭右开区间的处理时不同的。

  1. 循环条件从 left <=right 改为 left<right ,因为 left == right 在 [left,right) 上没有意义。
  2. 当 nums[mid] > target 时,right = mid ,而不是 right = mid - 1;

优化:

int mid = (left + right) / 2; 可以改为 int mid = left + ((right - left) / 2); 或 int mid = left + ((right - left) >> 1); 改为 int middle = left + ((right - left) >> 1);

int mid = (left + right) / 2;如果碰到 left 和 right 都接近 int 类型的极限,可能会溢出

int middle = left + ((right - left) >> 1); 是比特操作,让2进制的数右移一位,相当于除以2。


  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值