面接に必要な古典的なアルゴリズムの質問 (C 言語の実装)

目次

序文: この章では、leetcode の 3 つの古典的なトピックを紹介します。主なアイデアは次のとおりです。  

1: 剣はオファー 58 - II. 左回転文字列 - LeetCode を指します。

2: 977. 順序付けされた配列の二乗 - LeetCode                                                                                    

3:27. 要素の削除 - LeetCode                                                                                                             

                               


          タイトル説明:

        文字列を与え、整数 n を指定すると、文字列の最初の n 文字を文字列の末尾まで回転するように求められます。

        

この問題の解決策を紹介しましょう: -->

        解決策 1:暴力的な解決時間の計算量は o(n^2) です  

        アイデア: まず 1 文字を左に回転するコードを記述し、それを n 回実行します。

                文字を左回転するアイデア: まず最初の要素を tmp 変数で保存し、次に最初の要素の後ろにある要素を前に移動し、その後 tmp を最後の位置に置きます。

       写真:

        コード:

        

  while(n--)
    {
        char tmp=*s;
        int i =1;
        for(i=1;i<strlen(s);i++)
        {
            s[i-1]=s[i];//挪动元素
        }
        //最后一个字符改为原来的第一个
        s[i-1]=tmp;
    }

しかし、時間の複雑さが高すぎるため、ブルート フォース ソリューションは leetcode で実行されました。

        したがって、解決策を変更する必要があります。

解決策 2: 3 ステップの逆文字列メソッドの時間計算量は O(N) 空間 O(1)

        アイデア: まず文字列の最初の n 文字を反転し、次に n 以降の文字列を反転し、最後に全体の順序を反転します。文字列をその場で変更します。

        コードを記述するときは、文字列添字の最大数 n-1 に注意する必要があります。

コード:

void reverse(char** pps,int left,int right)
{
    while(left<right)
    {
        char tmp=(*pps)[left];
        (*pps)[left]=(*pps)[right];
        (*pps)[right]=tmp;
        left++;
        right--;
    }
}

char* reverseLeftWords(char* s, int n){
    reverse(&s,0,n-1);//逆置前n个
    reverse(&s,n,strlen(s)-1);//逆置n后面
    reverse(&s,0,strlen(s)-1);//整体逆置
    return s;
}

解決策 3 : 切断 + 結合 時間 O(n) スペース O(n)

        アイデア: 最初の n 文字を取り出し、「\0」文字を追加し、残りの文字を保存し、最後に 2 つの文字を結合し、最後の n 文字を前に置き、最初の n 文字を後ろにつなぎ合わせると、次のことが可能になります。達成するために。

        コード:

char* reverseLeftWords(char* s, int n){
    n=n%(strlen(s)+1);
    char* ret1=(char*)malloc(sizeof(char)*(n+1));//放要旋转的字符还得放'\0'
    char* ret2=(char*)malloc(sizeof(char)*(strlen(s)+1));
    //先放要旋转的字符串
    int i=0;
    int j=0;
    for(i=0;i<n;i++)
    {
        ret1[j]=s[i];
        j++;
    }
    ret1[j]='\0';
    j=0;
    for(i=n;i<strlen(s);i++)
    {
        ret2[j]=s[i];
        j++;
    }
    int k =0;
    while(ret1[k]!='\0')
    {
        ret2[j++]=ret1[k++];

    }
    ret2[j]='\0';
  
    return ret2;

}

要約: これら 3 つの方法の中で、2 番目の方法が間違いなく最良ですが、考えるのが最も困難でもあります。

        この質問を共有したら、次の質問に進みましょう。 

    

2:  977. 順序付き配列の二乗 - LeetCode                                                                                                                                                                                                メソッド 1:ソートとトラバーサル                                                                                                                      
アイデア: まず配列内のすべての要素を 2 乗し、それを解決するためにクイック ソートを追加します。時間計算量: O(nlogn) コード実装:
 //时间复杂度O(n),空间复杂度O(n),双指针
int* sortedSquares(int* nums, int numsSize, int* returnSize){
    int left=0;
    int right=numsSize-1;
    while(left<=right)
    {  
        if(nums[left]*nums[left]>nums[right]*nums[right])
        {
            int tmp=nums[right];
            nums[right--]=nums[left]*nums[left];
            nums[left]=tmp;
        }
        else
        {
           nums[right--]=nums[right]*nums[right];
        }
    }
    * returnSize=numsSize;
    return nums;
}
写真:                                                                                                                                                     
      
 方法 2:  配列は順序配列であることがわかっているため、正方形の値は両側に行くにつれて増加します。そのため、ダブル ポインター法を使用して問題を解決し、大きい要素を最後に配置します。
写真:
  コード:
 //时间复杂度O(n),空间复杂度O(n),双指针
int* sortedSquares(int* nums, int numsSize, int* returnSize){
    //新开辟的一块空间,
    int* ret=(int*)malloc(sizeof(int)*numsSize);
    int i =numsSize-1;
    int left=0;
    int right=numsSize-1;
    while(left<=right)
    {
        if(nums[left]<0)
            nums[left]=-nums[left];
        if(nums[left]>nums[right])
        {
            ret[i--]=nums[left]*nums[left];
            left++;            
        }
        else
        {
             ret[i--]=nums[right]*nums[right];
            right--;           
        }
    }
    * returnSize=numsSize;
    return ret;
}
この質問は共有されています -_-

3:27 . 要素の削除 - LeetCode                                                                                                     

 

   同じ要素を削除する: この質問についてはダブルポインタ法を直接説明しますが、暴力的な解決策については説明しません。

        ダブル ポインター メソッド: 2 つのポインターを使用します。1 つのポインターは配列全体の要素を走査するために使用され、もう 1 つのポインターは配列内の要素を変更するために使用されます。

 

        コード:

int removeElement(int* nums, int numsSize, int val){
    int fast=0;
    int slow=0;
    while(fast<numsSize)
    {
        if(nums[fast]!=val)
        {
            nums[slow]=nums[fast];
            slow++;
        }
        fast++;
    }
    return slow;
}

 この章の典型的なアルゴリズムの質問は終わりました。役に立ったと思われる場合は、高く評価してください。

        何か間違っている点がございましたら、ご指摘お待ちしております。

        

                               

おすすめ

転載: blog.csdn.net/2201_75964502/article/details/132637062