LeetCode算法题(15-19)

第15题:三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum

思路
使用3个指针,分别代表三元组中最左、中间和最右的数,然后通过中间的指针和最右指针的移动来遍历数组。

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
 int cmp(const void *a,const void *b)
{
    return *(int*)a - *(int*)b;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
       *returnSize = 0;
   if(numsSize < 3)  return NULL;
   

    qsort(nums,numsSize,sizeof(int),cmp);
    
   int **ans = (int **)malloc(sizeof(int *) * numsSize *numsSize);
   *returnColumnSizes = (int *)malloc(sizeof(int) * numsSize* numsSize) ;
   int left, mid, right, sum;
    
   
   for(left = 0;left < numsSize - 2;left++)
   {
       if(nums[left] > 0) return ans;
       if(left > 0 && nums[left] == nums[left-1])  continue;
       mid = left + 1;
       right = numsSize - 1;
       while(mid < right)
       {
           sum = nums[left] + nums[mid] + nums[right];
           if(sum == 0)
           {
               ans[*returnSize] = (int *)malloc(sizeof(int)*3);
             
                (*returnColumnSizes)[*returnSize] = 3;
                ans[*returnSize][0] = nums[left];
                ans[*returnSize][1] = nums[mid];
                ans[*returnSize][2] = nums[right];
                *returnSize+=1;     //注意,*的优先级与+ 相同,结合方向从有到左,,*returnSize++  等同于 *(returnSize++)
                while(mid < right && nums[mid] == nums[++mid]);   
                while(mid < right  && nums[right] == nums[--right]) ; 
           }
           else if(sum < 0)
           {
               mid ++;

           }
           else   right--;
           
       }
       
   }
    return ans;
}

第16题:最接近的三数之和
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest

int compare(const void *a, const void*b)
{
    return *(int *)a - *(int *)b;
}
int threeSumClosest(int* nums, int numsSize, int target){
    qsort(nums, numsSize, sizeof(int), compare);
    int left, mid, right, sum1, sum2;
    
    
    sum1 =  nums[0] + nums[1] + nums[2];
    
    for(left = 0; left < numsSize-2; left ++)
    {
        mid = left + 1;
        right = numsSize - 1;
        
        while(mid < right)
        {
            sum2 = nums[left] + nums[mid] + nums[right];
            if(abs(sum1 - target) > abs(sum2 - target))
            {
                sum1 = sum2;
                
            }
            if(sum2 >= target)  while(mid < right && nums[right] == nums[--right]);
            else    while(mid < right && nums[mid] == nums[++mid]); 
        }
    }
    return sum1;
}

第17题:电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number

思路
寻找字典序排列时每个字母位置字母出现的规律。具体见代码。

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

char ** letterCombinations(char * digits, int* returnSize){
    *returnSize = 0;
    int len = strlen(digits);
    if(len == 0)
    {
        
        return NULL;
    }
    
    
    char  f[8][5] = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    int i, j, k, t;
    int num[8], l[8];
    for( i = 0; i < len; i++)    //每个位置的数字对应的字母的个数
    {
        num[i] = strlen(f[digits[i]-'0'-2]);
    }
    for( i = 0; i < len; i++)    //第i个位置之前的排列数,即位置i上每个字母出现几个区间
    {
        if(i == 0) l[0] = 1;
        else l[i] =num[i-1] * l[i-1];
    }
    *returnSize = l[len-1] * num[len-1];
    int m[8];
    for(i = len-1; i >= 0; i--)    //第i个位置之后的排列数,即位置i上每个字母在一个区间出现几次
    {
        if(i == len-1) m[i] = 1;
        else m[i] = num[i+1] * m[i+1];
    }
    int tmp;
    char **ans = (char **) malloc ( sizeof(char *) * (*returnSize));
    for(i = 0; i < *returnSize; i++)
    {
        ans[i] = (char *) malloc(sizeof(char) * (len + 1));
        
    }
    /*数字所在位置为i,字母为数字对应的第j个字母,那么该字母出现在l[i]个区间内,
    每个区间长度为m[i],第k个区间位置为:k* m[i] *num[i]+ j *m[i]  ~ (k*m[i]*num[i] +j*m[i] + m[i]-1)*/
    for(i = 0; i < len; i++)   //i表示字母的位置
    {
        
        for(j = 0; j < num[i]; j++)   //j表示该字符是数字对应的字母的次序
        {
            
           for(k = 0; k < l[i]; k++)
           {
               tmp = k * m[i] *num[i] + j *m[i];
               for(t = 0; t < m[i]; t++)
               {
                   ans[tmp + t][i] = f[digits[i] - '0' -2][j];
                  
               }
           }

        }
    }
    for(i = 0; i < *returnSize; i++)
    {
        
        ans[i][len] = '\0';
    }
    return ans;
}

第18题:四数之和给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum

思路
与“三数之和”类似。

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
 int cmp(const void *a, const void *b)
 {
     return *(int *)a - *(int *)b;
 }
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes){
    *returnSize = 0;
    if(numsSize < 4 )  return NULL;
    
    qsort(nums, numsSize, sizeof(int), cmp);

    if((long)nums[numsSize-1] +nums[numsSize-2] + nums[numsSize-3] + nums[numsSize-4] < target)  return NULL;
    int i, j ,k ,t;
    
    long sum ,tmp;
    *returnColumnSizes = (int **)malloc(sizeof(int *) * numsSize*numsSize);
    int **ans = (int **)malloc(sizeof(int *) * numsSize*numsSize);
    for(i = 0; i < numsSize - 3; i++)
    {
        if(i > 0 && nums[i] == nums[i-1])  continue; 
        if((long)nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target) return ans;
        for(j = i + 1; j < numsSize -2; j ++)
        {
            if(j > i+1 && nums[j] == nums[j-1]) continue;
            if((long)nums[i] + nums[j] + nums[numsSize-1] + nums[numsSize-2] < target) continue;
            k = j + 1;
            t = numsSize - 1;
            tmp = nums[i] + nums[j];
            while(k < t)
            {
                
                sum = tmp + nums[k] +nums[t];
                if(sum == target) 
                {
                    ans[*returnSize] = (int *)malloc(sizeof(int) * 4);
                    (*returnColumnSizes)[*returnSize] = 4;
                    ans[*returnSize][0] = nums[i];
                    ans[*returnSize][1] = nums[j];
                    ans[*returnSize][2] = nums[k];
                    ans[*returnSize][3] = nums[t];
                    
                    *returnSize += 1;
                    while(k < t && nums[k] == nums[k+1]) k++;
                    while(k < t && nums[t] == nums[t-1]) t--;
                    k++;
                    t--;
                }
                else if(sum < target)  k++;
                else t--;

                
            }
        }
        
    }
    return ans;
}

第19题:删除链表的导数第N个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

来源:LeetCode
链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode) (leetcode-cn.com)

思路
先遍历链表,得到链表的长度,然后从头得到要删除结点的前一个结点,然后进行删除操作。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    struct ListNode *s, *t;
    t = s = head;
    int len = 0;;
    while(s)
    {
        s = s->next;
        len++;
    }
    int i;
    s = t;
    if(n == len) 
    {
        s = s->next;
        return s;
    }
    for(i = 0; i < len - n -1; i++)
    {
        s = s->next;
    }
    
    s->next = s->next->next;
    return t;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容