• Leetcode题解(一)


    1、Two Sum

    题目

    此题第一解题思路,就是最常见的方法,两个指针嵌套遍历数组,依次判断当前指针所指向的值是否满足条件。代码如下;

     1 class Solution {
     2 public:
     3     vector<int> twoSum(vector<int>& nums, int target) {
     4         int p1,p2;
     5         const int size = nums.size();
     6         for (p1 = 0;p1<size;p1++)
     7         {
     8             for(p2 = p1+1;p2<size;p2++)
     9                 if (target == nums[p1] + nums[p2])
    10                 {
    11                     break;
    12                 }
    13         }
    14         vector<int> res;
    15         res.push_back(p1+1);
    16         res.push_back(p2+1);
    17         
    18         return res;
    19     }
    20 };

    这种思路解决该问题的时间复杂度是O(n*n),虽然时间复杂度比较高,但是该算法是最直接也最容易想到的解决办法,能够解决题目所提出的要求。

    学过算法的同学都知道,几个比较常见的算法时间复杂度是O(n*n),O(nlogn),O(n),O(logn)。在现有算法的基础上进行算法优化也是一项比较好的能力,因此,我们还需要对之前的算法做一些优化,按照常规思路,我们猜想还有时间复杂度是O(nlogn)的算法能够解决该问题。看到时间复杂度为O(nlogn),第一反应就是“排序”,因为排序算法的时间复杂度是O(nlogn),所以,我们可以先对数据排序,然后采用夹逼的方式找到满足条件的数据。如果要对数据进行排序,则打乱了数据的原始顺序,因此排序的同时要记录各个数据的原始位置,如果遇到面试官出这种题,也需要问清楚是否能够改变原数据的位置,问清楚之后再想办法。代码如下

     1 struct node 
     2 {
     3     int value;
     4     int index;
     5 };
     6 bool Cmp( const node &v1, const node &v2)
     7 {  
     8     return v1.value < v2.value;//升序排列  
     9 }  
    10 class Solution {
    11 public:
    12     vector<int> twoSum(vector<int>& nums, int target) {
    13         int p1,p2;
    14         const int size = nums.size();
    15 
    16         vector<node> temp;
    17         node t;
    18         for (int i=0;i<size;i++)
    19         {
    20             t.value = nums[i];
    21             t.index = i;
    22             temp.push_back(t);
    23         }
    24 
    25         sort(temp.begin(),temp.end(),Cmp);
    26         p1 = 0;
    27         p2 = size-1;
    28         while (p1 <= p2)
    29         {
    30             if(temp[p1].value + temp[p2].value > target)
    31                 p2--;
    32             else if(temp[p1].value + temp[p2].value < target)
    33                 p1++;
    34             else
    35                 break;
    36         }
    37 
    38         //由于一定有解,因此不用判断解是否存在
    39         vector<int> res;
    40         int min = temp[p1].index > temp[p2].index ? temp[p2].index:temp[p1].index;
    41         int max = temp[p1].index < temp[p2].index ? temp[p2].index:temp[p1].index;
    42 
    43         res.push_back(min );
    44         res.push_back(max);
    45 
    46         return res;
    47     }
    48 };

     该算法的时间复杂度为O(nlogn),其主要是先排序后操作。

    到此我们可能回想还能不能对算法就行优化,使得算法的时间复杂度更低。比O(nlogn)复杂度更低的常规复杂度就是O(n),如果复杂度是O(n),意味着对数据只能进行多次访问遍历,不能有嵌套遍历这种方式,也就是遍历的时候需要做“记忆功能”,有记忆功能的结构,比如哈希,map等。因此可以采用如下的方法解决该问题:

     1 class Solution {
     2 public:
     3     vector<int> twoSum(vector<int> &nums, int target) {
     4         vector<int> result;
     5         result.clear();
     6         map<int,int> myMap;
     7         
     8         int i,temp;
     9         int length = numbers.size();
    10         map<int,int>::iterator it;
    11         myMap.insert(pair<int,int>(nums[0],0));
    12         for (i=1;i<length;i++)
    13         {
    14             temp = target - nums[i];
    15             it = myMap.find(temp);
    16             if (it!=myMap.end())
    17             {
    18                 result.push_back(it->second+1);
    19                 result.push_back(i+1);
    20                 break;
    21             }
    22             myMap.insert(pair<int,int>(nums[i],i));
    23         }
    24         
    25         return result;
    26 
    27     }
    28     
    29 };

     ------------------------------------------------------------------------------------------分割线---------------------------------------------------------------------------------------

     2 Add Two Numbers

    题目

     这道题主要考察指针的使用,灵活的使用指针是c++程序员必须的技能之一.代码如下:

     1 /**
     2  * Definition for singly-linked list.
     3  * struct ListNode {
     4  *     int val;
     5  *     ListNode *next;
     6  *     ListNode(int x) : val(x), next(NULL) {}
     7  * };
     8  */
     9 class Solution {
    10 public:
    11     ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    12         if (NULL == l1)//算法的鲁棒性
    13         {
    14             return l2;
    15         }
    16         if (NULL == l2)
    17         {
    18             return l1;
    19         }
    20 
    21         ListNode *head = new ListNode(9);//添加伪头部
    22         ListNode *tail = head;
    23         ListNode *p1 = l1;
    24         ListNode *p2 = l2;
    25         int c=0,temp;
    26 
    27         while(NULL != p1 && NULL != p2)
    28         {
    29             temp = (p1->val + p2->val + c)%10;
    30             c = (p1->val + p2->val + c)/10;
    31             tail->next = new ListNode(temp);
    32             tail = tail->next;
    33             p1 = p1->next;
    34             p2 = p2->next;
    35         }
    36 
    37         while (NULL != p1)
    38         {
    39             temp = (p1->val + c)%10;
    40             c = (p1->val + c)/10;
    41             tail->next = new ListNode(temp);
    42             tail = tail->next;
    43             p1 = p1->next;
    44         }
    45 
    46         while (NULL != p2)
    47         {
    48             temp = (p2->val + c)%10;
    49             c = (p2->val + c)/10;
    50             tail->next = new ListNode(temp);
    51             tail = tail->next;
    52             p2 = p2->next;
    53         }
    54         if (c!=0)
    55         {
    56             tail->next = new ListNode(c);
    57             tail = tail->next;
    58         }
    59 
    60         head = head->next;
    61         return head;
    62         
    63     }
    64 };

    -----------------------------------------------------------------------------------------分割线-----------------------------------------------------------------------------------------

    3、Longest Substring Without Repeating Characters

    题目

     题目意思:不含重复字母的最长子串

    字符串s[0,n-1],其子串表示为s[i,j],其中0<=i<=j<=n-1,通过这种表示方法,解决该题的暴力算法就是先确定一个子串(i,j),再判断该子串中是否有重复的字符,代码如下:

     1 class Solution {
     2 public:
     3     int lengthOfLongestSubstring(string s) {
     4         if("" == s)
     5             return 0;
     6 
     7         set<char> myset;
     8 
     9         int i,j;
    10         int max = 0;
    11         int length = s.length();
    12         for(i=0;i<length;i++)
    13         {
    14             myset.clear();
    15             for(j=i;j<length;j++)
    16             {
    17                 if(myset.find(s[j])!=myset.end())
    18                 {
    19                     break;
    20                 }
    21                 else
    22                 {
    23                     myset.insert(s[j]);
    24                 }
    25             }
    26             if(j-i >max)
    27                 max = j-i;
    28         }
    29         return max;
    30 
    31     }
    32 };

    算法时间复杂度很明显是O(n*n),因此这个算法让人不是很满意的,需要在此基础上优化,寻找是否存在O(nlogn)或者复杂度更低的算法。

    O(nlogn),意味着要对字符串做排序工作,对字符串排序是比较少有的操作,因此排除这种算法。

    在寻找不重复的最长子串时,通过在纸上画示意图可以得知,假设当前从下标[i]开始寻找,一直到下标[j]为止都还没有发现重复的字符,但是在下标[j+1]处,发现该字符与下标[k](i<=k<=j)处的字符一样。因此在做下一轮寻找时,需要从[k+1]做为起始字符进行寻找,代码如下:

     1 class Solution {
     2 public:
     3     int lengthOfLongestSubstring(string s) {
     4         if("" == s)
     5             return 0;
     6 
     7         set<char> myset;
     8 
     9         int i,j;
    10         int max = 1;
    11         int length = s.length();
    12         i=0;
    13         j=1;
    14         myset.clear();
    15         myset.insert(s[0]);
    16         for (;j<length;j++)
    17         {
    18             if(myset.end() == myset.find(s[j]))
    19                 myset.insert(s[j]);
    20             else//删除k之前的所有字符
    21             {
    22                 if(j-i > max)
    23                     max = j-i;
    24                 while(s[i] != s[j])
    25                 {
    26                     myset.erase(s[i]);
    27                     i++;
    28                 }
    29                 myset.erase(s[i]);
    30                 i++;
    31                 j--;
    32             }
    33         }
    34         if(j-i>max)
    35             max = j-i;
    36         
    37         return max;
    38 
    39     }
    40 };

    提交Accepted。

    算法时间复杂度分析,for循环停止条件是j=length,每次从集合set中还要删除一部分元素,因此复杂度为O(2n)。

    这种算法的思想和KMP算法的思想很类似。如果熟练了KMP算法,解决这道题就不在话下。

     <( ̄︶ ̄)>

    ------------------------------------------------------------------------------------------分割线---------------------------------------------------------------------------------------

    231 Power of  Two

    题目很简单,直接上代码,主要是掌握bitset的使用。

     1 class Solution {
     2 public:
     3     bool isPowerOfTwo(int n) {
     4         bitset<32> myset(n);
     5         if (n<=0)
     6         {
     7             return false;
     8         }
     9 
    10         if (1==myset.count() || 0==myset.count())
    11         {
    12             return true;
    13         }
    14 
    15         return false;
    16 
    17 
    18     }
    19 };
  • 相关阅读:
    第10组 Beta冲刺 (3/5)
    第10组 Beta冲刺 (2/5)
    第10组 Beta冲刺 (1/5)
    第10组 Alpha冲刺 (3/6)
    第10组 Alpha冲刺 (2/6)
    第10组 Alpha冲刺 (1/6)
    第一次作业
    第二次作业
    机器学习_第一次个人作业
    软工实践个人总结
  • 原文地址:https://www.cnblogs.com/LCCRNblog/p/4625266.html
Copyright © 2020-2023  润新知