开始了leetcode的刷题之路,话不多说,从头开始。。。
344.Reverse String
//my code
#include
using namespace std;
class Solution {
public:
string reverseString(string s) {
int numb = s.size();
string s1 = "";
for(int i = numb - 1; i >= 0; i--)
{
s1 += s[i];
}
return s1;
}
};
//others c code
char* reverseString(char* s) {
char *t,*r,tmp;
r=s;
t=s+strlen(s)-1;
while(s
总结:自己编写的思想就是利用for循环,从尾部到头部把一个个的字符加入到新建的空字符变量中,这样,最后生成的新字符串自然就实现了字符反转。
而看了别人用c写的代码,没有用到for循环,使用两个指针,一个指向第一个字符,一个指向最后一个字符,将两个字符实现交换,然后指向第一个字符的指针+1,指向最后一个字符的指针-1,这跟我的方法相比,只循环了一半的次数,就实现了字符反转,好吧。。
345.Reverse Vowels of a String
//My code
class Solution {
public:
string reverseVowels(string s) {
int numb = s.size();
string s1 = "", s2 = s;
for(int i = 0; i < numb; i++)
{
if( s[i] == 'a' || s[i] == 'A' || s[i] == 'e' || s[i] == 'E' || s[i] == 'i' || s[i] == 'I' || s[i] == 'o' || s[i] == 'O' || s[i] == 'u' || s[i] == 'U' )
{
s1 += s[i];
}
}
int n = 0;
for(int j = numb-1; j >= 0; j--)
{
if(s[j] == 'a' || s[j] == 'A' || s[j] == 'e' || s[j] == 'E' || s[j] == 'i' || s[j] == 'I' || s[j] == 'o' || s[j] == 'O' || s[j] == 'u' || s[j] == 'U' )
{
s2[j] = s1[n];
n++;
}
}
return s2;
}
};
//others code
class Solution {
public:
string reverseVowels(string s) {
int start = 0;
int end = s.size()-1;
while(start
总结:我的代码思路是:第一步提取出字符串中的所有元音字母,保存到一个字符串里面,这里面用到了一个for循环,下一步是从尾到头再遍历一遍字符串,如果遇到元音字母,则把刚刚提取出来的元音字母按照从小到大的顺序依次进行替换。
而别人的思路是设置两个指针,分别指向字符串的第一位和最后一位,然后进行一个while循环,对两个指针所指的字符进行分类判断,当前后指针都指向了元音字母,那么交换数据,如果前指针指向元音字符而后指针没有,那么后指针向前进一位,相反,前指针向前进一位,如果两个指针都没有指向元音字母,那么各进一位,知道前指针等于后指针,字符串全部遍历了一遍结束。整个代码还是只循环了一半的字符串长度的次数,而我的是循环了两遍,真的蠢哭了。
1. Two Sum
//My code
//功能:给定一个vector数组和一个目标数traget,若在数组中能寻找到两个数a,b,使得a+b=target,
则输出a,b对应的vertor下标[i,j];
class Solution {
public:
vector twoSum(vector& nums, int target) {
vector result;
int count = nums.size();
for(int i = 0; i < count-1; i ++)
{
for(int j = i+1; j < count; j++)
{
if(nums[i] + nums [j] == target)
{
result.push_back(i);
result.push_back(j);
}
}
}
return result;
}
};
//others code
class Solution {
public:
vector twoSum(vector& nums, int target) {
unordered_map hash;
unordered_map::iterator got;
int len = nums.size();
int idx1, idx2;
//将vector中的内容存储到关联容器,格式为(vector中的值,其对应的下标)。
for (int i = 0; i < len; i++) {
got = hash.find(nums[i]);
if (got == hash.end()) {
hash.insert(make_pair(nums[i],i));
} else {
got->second = i;
}
}
for (vector::const_iterator it = nums.begin(); it != nums.end(); ++it) {
if (hash.count(target-*it)) { //判断加法对应*it的另一个加数是否在容器中
idx1 = (it - nums.begin()); //若在,返回*it的位置索引
idx2 = hash[target-*it]; //并返回hash表中另一个加数对应的值
if (idx1 != idx2) {
break;
}
}
}
return {idx1,idx2};
}
};
总结:我的代码是很直观的思路,构建两个循环,查找两个数判断结果。时间复杂度为o(n^2);
别人的代码中用到了关联容器unordered_map,容器中保存的关键字是vector中的值,其值则是对应的vector中的下标。让后循环遍历vector,并在遍历中让target减去当前遍历vector位置的值,所得结果为该位置下所对应的另一个加数的值,然后在哈希表中查找,若找到,则表明vector容器中存在这样的一对值,加起来的结果为target,于是返回这两个值对应的下标。这种方式使得一次循环就能得出结果。
2. Add Two Numbers
//My code
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* Create() //创建一个头结点
{
ListNode * lNode = (ListNode*)malloc(sizeof(struct ListNode));
lNode->val = 0;
lNode->next = NULL;
return lNode;
}
void Insert(ListNode* l,int a)
{
ListNode *pNode;
while(l->next != NULL)
l = l->next;
pNode = (ListNode*)malloc(sizeof(struct ListNode));
pNode->val = a;
pNode->next = NULL;
l->next = pNode;
}
int Read(ListNode* l,int x) //头结点不计入
{
int value;
ListNode *pNode = l;
for(int i = 1; i < x; i++)
{
pNode = pNode->next;
}
value = pNode->val;
return value;
}
int Size(ListNode *l) //头结点不计入
{
ListNode *pNode = l;
int count = 0;
while(pNode != NULL)
{
pNode = pNode->next;
++count;
}
return count;
}
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int size1,size2,min,max,value,value1,value2,fillout = 0;
ListNode *pNode;
pNode = Create();
size1 = Size(l1);
size2 = Size(l2);
if(size1 >= size2)
{
max = size1;
min = size2;
}
else
{
max = size2;
min = size1;
}
for(int i = 1, j = 1 ; i <= max; i++,j++)
{
if(size1 >= size2)
{
value1 = Read(l1,i);
if(j <= min)
{
value2 = Read(l2,j);
}
else
{
value2 = 0;
}
}
else
{
value1 = Read(l2,i);
if(j <= min)
{
value2 = Read(l1,j);
}
else
{
value2 = 0;
}
}
value = value1 + value2 + fillout;
if(value >= 10)
{
value = value % 10;
Insert(pNode,value );
fillout = 1;
}
else
{
Insert(pNode,value );
fillout = 0;
}
}
if(fillout == 1)
{
Insert(pNode,fillout);
}
return pNode->next;
}
};
//others code
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2)
{
int c = 0;
ListNode newHead(0);
ListNode *t = &newHead;
while(c || l1 || l2)
{
c += (l1? l1->val : 0) + (l2? l2->val : 0);
t->next = new ListNode(c%10);
t = t->next;
c /= 10;
if(l1) l1 = l1->next;
if(l2) l2 = l2->next;
}
return newHead.next;
}
};
总结:这一题花了很长很长的时间。。。由于没正确的看懂题意,然后写的代码数及质量也很低下,跟优秀的代码比起来真是相差太多了。第一个没弄懂的地方就是题目提示中给出的
ListNode(int x) : val(x), next(NULL) {}
就表示已经提供了初始化的方式,然而我没看明白,就都自己写出来了;其次是相加的过程中一开始一直以为是从后往前加;最恼人的地方时发现自己写这样的的代码中太过于喜欢用for结构而不善于用while循环,导致代码质量和效率都差了好多好多。从别人的代码中也可以看出许多的两点出来,首先就是while循环简单明了,相加的过程中,整型变量c既求出了加数与10的取模量,又保证了是否要往前进一位,while(c)中的c就是判断最后一位是否有进位的要求。
The pseudocode is as following(本题算法伪代码如下):
Note that we use a dummy head to simplify the code. Without a dummy head, you would have to write extra conditional statements to initialize the head's value.
大致说一下题:
要求:给一个字符串,求其中最长无重复字符的子串的长度
例子:
给出"abcabcbb",符合要求的子串是"abc", 其长度为 3.
给出"bbbbb", 符合要求的子串是 "b", 其长度为1.
给出"pwwkew",符合要求的子串是 "wke", 其长度为 3.
注意答案要求的是子串, 因此上面的例子中"pwke" 是一个字字符序列,而不是一个子串.
算法思路:这里面需要做两件事情
第一是需要能够判别出前面重复出现过的字符。
第二是需要统计未重复出现的连续字符长度,并且其中最长的作为结果。
我的代码(思路):
采取的是超级笨的办法,用一个新的字符串变量收集遍历的字符,如果没有出现,就加进去,并统计新子串的长度,如果重复出现了,将遍历的起始位置加一,重新统计,算算时间复杂度,几乎达到n^3,真是愚蠢。虽然结果正确,但是对于较长的字符,效率较低,因此提交的时候未能通过。。。
//My code
class Solution {
public:
bool IsInclude(string s,char a)
{
int len = s.size();
int i = 0;
while(i < len)
{
if(s[i] == a)
return true;
i++;
}
return false;
}
int lengthOfLongestSubstring(string s) {
int len, lensub, i, j;
int maxlensub = 0;
len = s.size();
string substring = "";
for(int i = 0; i < len; i++)
{
substring += s[i];
if(maxlensub < 1)
maxlensub = 1;
for(int j = i + 1; j < len; j++)
{
if(false == IsInclude(substring,s[j]))
{
substring += s[j];
}
else
{
substring = "";
break;
}
lensub = substring.size();
if(maxlensub < lensub)
maxlensub = lensub;
if(maxlensub >= len - i)
return maxlensub;
}
}
return maxlensub;
}
};
对于需要判别重复出现的字符这个要求,怎样才能做到呢,别人给出的一种巧妙的方法。我们知道,每个字符所对应的ASCII码是不同的,因此我们完全可以申请一个可以统计所有字符大小(比如256?)的空间的数组或vector容器。一开始的时候,我们给定他们一个统一的标记-1,然后再遍历给定的字符串,在遍历的过程中,判断该字符对应的ACSII码的位置是否为-1,如果为-1,说明前面没有出现过,我们给他重新作标记,以表示出现了,如果不为-1,说明该字符前面出现过,这样我们需要作别的处理,这个处理的目的就是为了下面做的事,也就是统计最长子串所做。
那么该怎么统计最长子串的长度呢:
假设我们的字符串s为adcgacdg:
申请一个vector
看下面的代码,区区9行就实现了要求,而且时间复杂度为o(n),简直是神来之笔啊。
int lengthOfLongestSubstring(string s) {
vector dict(256, -1);
int maxLen = 0, start = -1;
for (int i = 0; i != s.length(); i++) {
if (dict[s[i]] > start)
start = dict[s[i]];
dict[s[i]] = i;
maxLen = max(maxLen, i - start);
}
return maxLen;
}