今天开始在算法打拼力

为了时间效率,直接做题记忆,而不是非要搞懂每个概念名词,不然做到猴年马月去

复习的最好方式就是直接在力口做一遍,做得出就是会了,或者说记住了//

看题目,记题解,默题解,以及最后快速复习

**

第一题 : Two Sum

**
链接地址

Given an array of integers, return indices(index 的复数形式之一) of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:
Given nums = [2 ,7, 11 ,15], target=9;

Because nums[0] + nums[1] = 2 + 7 = 9 ,return [0 , 1].

ps:想一会想不出就别嗯想了

关键在于怎么同一个元素不使用两边呢?假设数组就三个元素,target=B+C,而二重循环A+B,A+C,最后B+C就会使用两次元素。。
不懂,不会

官方题解:使用java
不要太纠结文字游戏了,这里两次应该是指不能同一个位置用两次,2+2=4这样自己加自己
但是可以两个位置相同数值,比如【2,2,3,4】如果目标是4,那么要求返回应该是【0,1】而不是【0,0】

方法一:遍历每个元素x,并查找是否存在与target-x相等的元素。(那么先自己写代码,不准照抄)

参考高赞题解
C#

public class Solution
{public int[] TwoSum(int[] nums, int target) {for(int i=0;i<nums.Length;i++)//这里Length-1也对{for(int j=i+1;j<nums.Length;j++)//最后一个不会与自己相加,因为j=i+1{if(nums[i]+nums[j]==target)return new int[] {i,j};、}}return new int[] {0,0};//官方java中用的是抛出异常//不写这句的话如果没有满足条件的情况就会没有返回值,出错}
}

(先复制到notepad再复制到这就没bug了)

时间复杂度O(n^2)对于每个元素,遍历数组的剩余部分来查找对应的目标元素,耗费O(n)的时间
(没毛病,ABCD,虽然循环里B只与CD查找,但在A的循环中AB也查找过了,所以每个元素都遍历了剩余元素)
空间复杂度O(1)
复杂度分析(课本p38页)

c++

class Solution {public:vector<int> twoSum(vector<int>& nums, int target) {int i,j;for(i=0;i<nums.size()-1;i++)//写上减1也是一样,上面的最后一步不执行so{for(j=i+1;j<nums.size();j++)//nums.size(){if(nums[i]+nums[j]==target){return {i,j};}}}return {i,j};};
};

方法二: 两边哈希表
课本p246,哈希表又叫散列表

为了对运行时间复杂度进行优化,我们需要一种更有效的方法来检查数组中是否存在目标元素。如果存在,我们需要找出它的索引。保持数组中的每个元素与其索引相对应的最好方法是哈希表。
通过以空间换取速度的方式,我们可以将查找时间从O(n)降低到O(1)。哈希表支持以近似恒定的时间进行快速查找。
使用两次迭代,在第一次迭代中,将每个元素的索引和值添加到表中。在第二次迭代中检查每个元素对应的目标元素(target-nums[i])是否存在于表中。

C#中,哈希表使用Dictionary类来实现,虽然不熟练字典是什么,但是可以先通过这个例子学习并记住这次的用法

关于C#哈希表,可见菜鸟教程C#集合

再次提醒,不要照抄代码,不要照抄代码,不要照抄代码!这样偷懒毫无意义!懒惰是万恶之源!

    public int[] TwoSum(int[] nums, int target){Dictionary<int, int> kvs = new Dictionary<int, int>();for (int i = 0; i < nums.Length; i++){//这里注意,判断的是如果输入数值与之前输入 过 的某个数值相同如【2,4,3,4】//之前输入了一个4,再输一次包含才是trueif (kvs.ContainsKey(nums[i])){//这时显然如果目标是该值乘二,那么返回这两个值即可if (nums[i] * 2 == target){return new int[] { kvs[nums[i]],i };}}else{kvs.Add(nums[i], i);}}for (int i = 0; i < nums.Length; i++){int complement = target - nums[i];//这里的条件和上面不同,这里是不能本身用两次,比如目标为4,【2,3,4,5】时//不能返回【0,0】//哪其实为什么还需要上面的条件呢,不明白,有这个不久够了吗?//因为上面在写入字典笨if (kvs.ContainsKey(complement)&&kev[complement]!=i){return new int[] { i, kvs[complement] };}}//没有答案时返回【0,0】return new int[] { 0, 0 };}

这个字典确实让数组中的元素和索引对应了,哪这和数组有什么区别呢,不也是一个数据一个索引?
但是!这里确实没有二重循环了,之前一次循环取所有数据,第二次循环将取出的数据(当然是经过和目标值表达式得到的)和其他的进行比较,
两边哈希表指第一遍将索引和值添加到表里,第二次直接搜索,一次循环还是取数据,关键在于这个ContainsKey这个方法吧,这个让我们省略了一个循环来比较值是否相等

时间复杂度O(n),我们把包含有n个元素的列表遍历两次。哈希表将时间缩短到O(1),
空间复杂度O(n),所需额外空间取决于哈希表中存储的元素数量

c++

class Solution {public:vector<int> twoSum(vector<int>& nums, int target) {map<int,int> a;//建立hash表存放数组元素vector<int> b(2,-1);//存放结果for(int i=0;i<nums.size();i++)a.insert(map<int,int>::value_type(nums[i],i));//注意小写for(int i=0;i<nums.size();i++){if(a.count(target-nums[i])>0&&(a[target-nums[i]]!=i))//判断是否找到目标元素且目标元素不能是本身{b[0]=i;b[1]=a[target-nums[i]];break;//使用break跳出}}return b;//要存在b里再输出。。};
};

注:该方法用 map 实现,map 是 STL 的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在 map 中出现一次,第二个可能称为该关键字的值)的数据处理能力
STL是Standard Template Library的简称,中文名标准模板库,菜鸟教程也有讲

    vector<int> a ;                                //声明一个int型向量avector<int> a(10) ;                            //声明一个初始大小为10的向量vector<int> a(10, 1) ;                         //声明一个初始大小为10且初始值都为1的向量vector<int> b(a) ;                             //声明并用向量a初始化向量bvector<int> b(a.begin(), a.begin()+3) ;        //将a向量中从第0个到第2个(共3个)作为向量b的初始值int n[] = {1, 2, 3, 4, 5} ;vector<int> a(n, n+5) ;              //将数组n的前5个元素作为向量a的初值vector<int> a(&n[1], &n[4]) ;        //将n[1] - n[4]范围内的元素作为向量a的初值

方法三:一遍哈希表
在进行迭代并将元素插入表的同时,检查是否已经存在对应的目标元素。

    public int[] TwoSum(int[] nums, int target){Dictionary<int, int> kvs = new Dictionary<int, int>();for (int i = 0; i < nums.Length; i++){int complement = target - nums[i];if (kvs.ContainsKey(complement) && kvs[complement] != i){return new int[] { i, kvs[complement] };}//需要对重复值进行判断,若结果包含了重复值,则已经被上面给return了;所以此处对于重复值直接忽略//举例法,如果是两个重复值,则被上一步return//如果不是,我们只需要其中一个即可,就算答案包含此值if (!kvs.ContainsKey(nums[i])){kvs.Add(nums[i], i);}}return new int[] { 0, 0 };}

时间复杂度O(n),
空间复杂度O(n),

c++

class Solution {public:vector<int> twoSum(vector<int>& nums, int target) {map<int,int> a;//提供一对一的hashvector<int> b(2,-1);//用来承载结果,初始化一个大小为2,值为-1的容器bfor(int i=0;i<nums.size();i++){if(a.count(target-nums[i])>0&&(a[target-nums[i]]!=i)){b[0]=a[target-nums[i]];b[1]=i;break;}a[nums[i]]=i;//反过来放入map中,用来获取结果下标}return b;};
};

//
软软官方的C#字典类注解

别玩了大哥,不要畏惧困难,克服他才能提升自己的能力

搜索得 map和unordered_map

需要引入的头文件不同
map: #include < map >
unordered_map: #include < unordered_map >
内部实现机理不同
map: map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树,而AVL是严格平衡二叉搜索树),红黑树具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉搜索树(又名二叉查找树、二叉排序树,特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值)存储的,使用中序遍历可将键值按照从小到大遍历出来。
unordered_map: unordered_map内部实现了一个哈希表(也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用)。因此,其元素的排列顺序是无序的。哈希表详细介绍
优缺点以及适用处
map:
优点:
有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作
红黑树,内部实现一个红黑书使得map的很多操作在lgn的时间复杂度下就可以实现,因此效率非常的高
缺点: 空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间
适用处:对于那些有顺序要求的问题,用map会更高效一些
unordered_map:
优点: 因为内部实现了哈希表,因此其查找速度非常的快
缺点: 哈希表的建立比较耗费时间
适用处:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map
总结:
内存占有率的问题就转化成红黑树 VS hash表 , 还是unorder_map占用的内存要高。
但是unordered_map执行效率要比map高很多
对于unordered_map或unordered_set容器,其遍历顺序与创建该容器时输入的顺序不一定相同,因为遍历是按照哈希表从前往后依次遍历的
map和unordered_map的使用
unordered_map的用法和map是一样的,提供了 insert,size,count等操作,并且里面的元素也是以pair类型来存贮的。其底层实现是完全不同的,上方已经解释了,但是就外部使用来说却是一致的。

第二题:Reverse Integer

Given a 32-bit signed integer, reverse digits of an integer.

Example 1: Input : 123 Output 321
Input: -123 Output -321;
Input: 120 Output 21;

Note:
Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range:[−2^31 ,2^31 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

ps:第一个问题是2的31次方怎么表示来着。忘了,
不会呢,能不能一个一个取到某个char数组里,,然后输出。。符号?0的话就判断一下就行了吧

傻逼了,看到评论里才想起来转成String不是什么char数组啊操,ToString忘了?然后再ToInt。。

那么学会两种解法,一转成字符串,二数学法

int是32位有符号整数类型,long是64位,short是16位
痛苦,找不到C#的字符串解法答案

方法一:字符串

先贴上大佬的c++

public:int reverse(int x){long result;if(x==INT_MIN)//int_min?等于最小,为什么就返回0?{//因为反转之后肯定超出,,注意是反转后return 0;}if(x<0){return -reverse(-x);}stringstream ss;ss<<x;string tmpStr;ss>>tmpStr;  int tmpStrSize=int(tmpStr.size());//size居然不是int型的吗string resultStr;for(int index=tmpStrSize-1;index>=0;index--){resultStr.push_back(tmpStr[index]);//push_back?}ss.clear();//clear又是什么;ss<<resultStr;//输入stringss>>result;//输出int。。if(result>INT_MAX){return 0;}return int(result);}};

ps:为什么评论会说用long犯规?

不知道就搜索!!!!!!!!

push_back()函数的用法
函数将一个新的元素加到vector的最后面,位置为当前最后一个元素的下一个元素
pop_back() //移除最后一个元素
clear() //清空所有元素
empty() //判断vector是否为空,如果返回true为空
erase() // 删除指定元素

C++中定义了三个类:istringstream,ostringstream和stringsteam,分别用来进行流的输入,输出和输入输出操作。主要用来进行数据类型的转换。,,就像上面那样

而C/C++整型上下限,即常量INT_MAX和INT_MIN分别表示最大,最小整数,定义在头文件limits.h中

哪c#里有这个好东西吗。。应该是string或Array里的方法来用

方法二:数学法

c++

class Solution {public:int reverse(int x) {int rev = 0;while (x != 0) {int pop = x % 10;//取个位x /= 10;//去个位if (rev > INT_MAX/10 || (rev == INT_MAX / 10 && pop > 7)) return 0;if (rev < INT_MIN/10 || (rev == INT_MIN / 10 && pop < -8)) return 0;//之所以在这写,是因为下一步就会产生溢出了,如果会的话要提前就返回rev = rev * 10 + pop;//累加}return rev;}
};

ps:2^31-1=2147483647 , -2^31=-2147483648 另外评论区好像还有很多高级的解法, C# 就是把INT_MAX改成int.MaxValue就行了

另外看到更棒的,关键就是判断溢出

class Solution {public:
{long n = 0;while(x != 0) {n = n*10 + x%10;x = x/10;}return (int)n==n? (int)n:0;//类型转换位int的话如果溢出必然不会和原来相等了
}

java, c#,c++都是这样写,

**

第三题 palindrome

**

Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.

Example 1:

Input: 121
Output: true

Example 2:
Input: -121;
Output: false
Explanation: From left to right, it reads -121.From right to left ,it becomes 121-.Therefore it is not a palindrome.

Follow up:
Could you solve it without converting the integer to a string?

ps:首先,不能将int转位string,那么我的思路是取末尾取首位(取首位除了while(x!=0)还有什么更好的方法吗),偶数直接循环总长/2,奇数也是,不用在意最后剩的数(但是你怎么知道int型的长度)

官方:方法一:反转一半数字
负数一定不是,除了0以外大于0的个位是0的也不是。。其实将数字本身反转与原数字相等就行,但是可能会溢出,所以可以将后一半取出反转与前一半相同就是回文了。

c++

class Solution {public:bool isPalindrome(int x) {if (x < 0 || (x % 10 == 0 && x != 0)) {return false;}int revertedNumber = 0;while (x > revertedNumber) {revertedNumber = revertedNumber * 10 + x % 10;x /= 10;}return x == revertedNumber || x == revertedNumber / 10;}
};

c#,将public后的:和最后的;去掉就行

这个取个位并且原数字去个位的和上面相同。只不过把条件直接放在了return里而已,这里的while循环正常两种情况,一,位数为偶数位,如果是回文,如123321,则取到123与原123相等,如果不是回文,则小于或大于取出的,124与123,122与123,这里大于原本用意是位数多的数自然比位数少的大,最后12与1234(这类似于奇数位),122与123,而条件是return里

对于我而言,问题关键在于怎么判断已经取了一半

对于不具体的问题最好的办法就是举例子思考

第四题 Roman To Integer

Roman numerals are represented by seven different symbols: I V X L C D and M.
1 5 10 50 100 500 1000

XII = 12 , XXVII =27

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we substract it making four. The same principle applies to the number nine, which is written as IX.

Given a roman numeral, convert it to an integer. Input is guaranteed to be within the ranger from 1 to 3999.

ps: 放到一个数组里?这样通过索引来判断,小在前用减法,大在前用加法,并且直接根据索引来得值。。说得挺好倒是写出来。。
怎么取字符串的每个字符来着。愣住

高赞大佬的思路 C#
注意读题,有且仅有六种使用减法情况

public class Solution {public int RomanToInt(string s) {s=s.Replace("IV","Y");//关键在于这个replace方法,因为特殊的只有这些,所以转换了就好判断了s=s.Replace("IX","T");s=s.Replace("XL","U");s=s.Replace("XC","R");s=s.Replace("CD","O");s=s.Replace("CM","W");int sum=0;int i=0;for (i=0;i<s.Length;i++){switch (s[i]){case 'M':sum+=1000;break;case 'W':sum+=900;break;case 'D':sum+=500;break;case 'O':sum+=400;break;    case 'C':sum+=100;break;case 'R':sum+=90;break;case 'L':sum+=50;break;case 'U':sum+=40;break;case 'X':sum+=10;break;case 'T':sum+=9;break;case 'V':sum+=5;break;case 'Y':sum+=4;break;case 'I':sum+=1;break;}}return sum;}
}

大佬的c++

class Solution {public:int romanToInt(string s) {unordered_map<string, int> m = {{"I", 1}, {"IV", 3}, {"IX", 8}, {"V", 5}, {"X", 10}, {"XL", 30}, {"XC", 80}, {"L", 50}, {"C", 100}, {"CD", 300}, {"CM", 800}, {"D", 500}, {"M", 1000}};int r = m[s.substr(0, 1)];for(int i=1; i<s.size(); ++i){string two = s.substr(i-1, 2);string one = s.substr(i, 1);r += m[two] ? m[two] : m[one];}return r;}
};

首先unordered_map内部实现的就是一个哈希表,substr是取字符串指定位置开始,指定长度,只有一个数字意味着一直取到结尾
这个三目运算符真让人在意,m[two]是一个条件。。

没错m[two]是一个条件,是否存在m[two]

另外IV是3这样也让人在意啊

构建一个字典记录所有罗马数字子串,注意长度为2的子串记录的值是(实际值 - 子串内左边罗马数字代表的数值)
这样一来,遍历整个 s 的时候判断当前位置和前一个位置的两个字符组成的字符串是否在字典内,如果在就记录值,不在就说明当前位置不存在小数字在前面的情况,直接记录当前位置字符对应值
举个例子,遍历经过 IV 的时候先记录 I 的对应值 1 再往后移动一步记录 IV 的值 3,加起来正好是 IV 的真实值 4。

妙啊,因为类似用了一个累加器,先将第一位存进来,(因为特殊的只有且都是两位的)比如对于前两位来说,只有两种可能,特殊的:将已记录的加上特殊的,普通的,直接已记录的加上后一位,之后逐位往后判断,其实自己举列子想想就很容易明白,

大概是,想用很简单的操作,就是逐位判断并累加,那么限制条件在于特殊情况怎么解决,这就是这题的关键,那么剩下的工作就是怎么解决这个问题,而方法就是在累加时同时判断下一位是否和当前位组成特殊

但是好慢!,占用也好大。。好像不用字典用switch会块,但是c++里switch

**

第五题 Longest Common Prefix

**

Write a function to find the longest common prefix string amongst an array of strings.

If there is no common prefix , return an empty string " ".

common prefix 公共前缀

Example1:

Input :[“flower” ,“flow”, “flight”]
Output: “fl”

Example 2:
Input:[“dog”, racecar", “car”]
Output: " "

Note: All given inputs are in lowercase letters a-z.

我给跪了,居然有这么多解法。。

官方题解

方法一:横向扫描

用 LCP(S1…Sn )表示字符串 S1…Sn的最长公共前缀。
可以得到以下结论:
LCP(S1…Sn)=LCP(LCP(LCP(S1,S2),S3),…Sn)
基于该结论,可以得到一种查找字符串数组中的最长公共前缀的简单方法。依次遍历字符串数组中的每个字符串,对于每个遍历到的字符串,更新最长公共前缀,当遍历完所有的字符串以后,即可得到字符串数组中的最长公共前缀。

如果在尚未遍历完所有的字符串时,最长公共前缀已经是空串,则最长公共前缀一定是空串,因此不需要继续遍历剩下的字符串,直接返回空串即可。

ps:那么问题就是判断公共字符的方法是什么呢?

class Solution {public:    string longestCommonPrefix(vector<string>& strs)    {        if(!strs.size())//初始就是空串的话        {            return "";        }        string prefix=strs[0];        for(int i=1;i<strs.size();i++)//遍历数组        {            prefix=longestCommonPrefix(prefix,strs[i]);//函数重载,不重载也行感觉            if(!prefix.size())//如果已经是空串就直接返回就行            {                return "";            }        }        return prefix;    }string longestCommonPrefix(const string& str1,const string& str2)    {        int length=min(str1.size(),str2.size());//取两个字符串长度最小值        int index=0;//variable declaration in condition must have an initializer,所以不能在while里声明        while(index<length&&str1[index]==str2[index])//字符串原来可以像数组一样用。。        {            index++;        }        return str1.substr(0,index);//substr方法    }};

再来看看这个const是什么

分为const形参和非const形参,配合&取地址符一起使用,这种用法和值传递的效果一样,但引用的效率更高,
对实参有要求,普通形参不用加const,因为形参不会改变实参,函数只是操作实参的副本,但是如果是引用或指针形参,则可以改变实参的值,所以除非实参是非const,否则就要加上const来避免

反正先记着吧

方法二:纵向扫描
方法一是横向扫描,依次遍历每个字符串,更新最长公共前缀。另一种方法是纵向扫描。纵向扫描时,从前往后遍历所有字符串的每一列,比较相同列上的字符是否相同,如果相同则继续对下一列进行比较,如果不相同则当前列不再属于公共前缀,当前列之前的部分为最长公共前缀。

class Solution {public:    string longestCommonPrefix(vector<string>& strs)    {        if(!strs.size())        {            return "";        }        for(int i=0;i<strs[0].size();i++)        {            char c=strs[0][i];//从前往后取第一个字符串的每个元素            for(int j=1;j<strs.size();j++)//取后面每个字符串的对应元素            {                if(i==strs[j].size()||strs[j][i]!=c)//谁短听谁的,以及不同时就返回                {                    return strs[0].substr(0,i);                }            }        }        return strs[0];//只有一个字符串的时候   }
};

方法三,分治
注意到 LCP\textit{LCP}LCP 的计算满足结合律,有以下结论:
LCP(S1…Sn)=LCP(LCP(S1…Sk),LCP(Sk+1…Sn))
其中 LCP(S1…Sn) 是字符串 S1…Sn 的最长公共前缀,1<k<n
基于上述结论,可以使用分治法得到字符串数组中的最长公共前缀。对于问题 LCP(Si⋯Sj),可以分解成两个子问题 LCP(Si…Smid) 与 LCP(Smid+1​…Sj​),其中 mid=i+j/2。对两个子问题分别求解,然后对两个子问题的解计算最长公共前缀,即为原问题的解。

class Solution {public:    string longestCommonPrefix(vector<string>& strs)    {        if(!strs.size())        {            return "";       }        else        {            return longestCommonPrefix(strs,0,strs.size()-1);        }    }string longestCommonPrefix(const vector<string>& strs,int start,int end)    {        if(start==end)        {            return strs[start];//跳出递归        }        else        {            int mid=(start+end)/2;            string lcpLeft=longestCommonPrefix(strs,start,mid);            string lcpRight=longestCommonPrefix(strs,mid+1,end);            return commonPrefix(lcpLeft,lcpRight);        }    }string commonPrefix(const string& lcpLeft,const string& lcpRight)    {        int minLength=min(lcpLeft.size(),lcpRight.size());        for(int i=0;i<minLength;i++)        {            if(lcpLeft[i]!=lcpRight[i])            {                return lcpLeft.substr(0,i);            }        }        return lcpLeft.substr(0,minLength);//这里为什么一定是left?//笨?都可以,不管是left长还是right长,反正返回都一样    }};

这个不是很明白

关键在于中间这个递归的方法,
怎么想到要递归的?因为方法本身功能就是二分,如果需要不断二分,则调用本身二分提供的功能就行了

思路是: 总之最终还是要回到两个字符串相比较,只不过这次我们是要不断分成两份,最终分到两个字符串为止,
偶数好说,奇数其实也差不多,每次右边都会分成偶数,left不断分,直到分成3个字符串时,必定变成(0,1)和(2),然后将(0,1)结果再与(2)比较,

递归在于调用自身,这里可以用偶数想,(都一样),目的是不断二分,二分的是索引,可以先正向思考,从(0,1)开始。
比较两个字符串的方法都一样,(应该是先写出了这个),那么可知我们还是需要得到字符串,只有两个的话完全就可以直接strs[0]和strs[1]了,
那么再想想4个,(0,1,2,3),实现二分就是简单地用 索引/2 ,而且要用(开始索引+结束索引)/2,因为算(2+3)/2=2,(因为本身递归,只用/2这个方法)所以如果这里要实现,我们就应该

结束条件就是start=end,取得字符串

之后再细想吧,好绕

方法四:二分查找
显然,最长公共前缀的长度不会超过字符串数组中的最短字符串的长度。用 minLength表示字符串数组中的最短字符串的长度,则可以在 [0,minLength]的范围内通过二分查找得到最长公共前缀的长度。每次取查找范围的中间值 mid,判断每个字符串的长度为 mid 的前缀是否相同,如果相同则最长公共前缀的长度一定大于或等于 mid,如果不相同则最长公共前缀的长度一定小于 mid,通过上述方式将查找范围缩小一半,直到得到最长公共前缀的长度。

刚才我们二分的是数组,这次是先找出最短字符串,然后二分这个字符串,

返回容器中最小值和最大值的指针。max_element(first,end,cmp);其中cmp为可选择参数!

class Solution {public:    string longestCommonPrefix(vector<string>& strs)    {        if(!strs.size())        {            return "";        }        int minLength=min_element(strs.begin(),strs.end(),[](const string& s,const string& t){return s.size()<t.size();})->size();        int low=0,high=minLength;        while(low<high)        {            int mid=(high-low+1)/2+low;            if(isCommonPrefix(strs,mid))            {                low=mid;            }            else            {                high=mid-1;            }        }        return strs[0].substr(0,low);    }    bool isCommonPrefix(const vector<string>& strs,int length)    {        string str0=strs[0].substr(0,length);        for(int i=1;i<strs.size();i++)        {            string str=strs[i];            for(int j=0;j<length;j++)            {                if(str0[j]!=str[j])                {                    return false;                }            }        }        return true;    }
};

有点复杂的样子,先放一边。另外c#还没写呐

LeetCode算法题个人笔记【简单1-5】【c#和c++】相关推荐

  1. LeetCode算法题个人笔记【数组】【简单1-5】【c++】

    资料来源于leetcode官网 记得多看评论! 听从大佬建议从同一类型题目开始做,首先决定做数组! 前面还有三道简单题已经做过了.共47道简单题 ** 第一题:搜索插入位置 ** 给定一个排序数组和一 ...

  2. LeetCode算法题个人笔记【数组】【简单6-10】【c++】

    ** 第六题:还是杨辉三角 ** 和 118 题 一样,依旧是杨辉三角.区别在于之前是输出所有层的数,这道题只需要输出第 k 层的数. 意思是说,我们只用一行vector< int> 就行 ...

  3. leetcode 算法题849 (简单240) 仅仅反转字母

    leetcode 算法题849 (简单240) 仅仅反转字母 题目介绍 给定一个字符串 S, 返回 "反转后的" 字符串, 其中不是字母的字符都保留在原地, 而所有字母的位置发生反 ...

  4. 【算法】LeetCode算法题-Remove Duplicates from Sorted Array

    这是悦乐书的第149次更新,第151篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第8题(顺位题号是26).给定一个已经排序(由小到大)的整数数组(元素可以重复),计算其 ...

  5. LeetCode算法题整理(200题左右)

    目录 前言 一.树(17) 1.1.后序遍历 1.2.层次遍历 1.3.中序 1.4.前序 二.回溯(20) 2.1.普通回溯 2.2.线性回溯:组合.排列.子集.分割 2.3.矩阵回溯 三.二分查找 ...

  6. Leetcode算法题:两个有序数组求中位数

    Leetcode算法题:两个有序数组求中位数 要求时间复杂度为O(log(m+n)) 思路: 暴力解决:合并数组并排序,简单且一定能实现,时间复杂度O(m+n) 由于两个数组已经排好序,可一边排序一边 ...

  7. LeetCode算法题-Nth Digit(Java实现)

    这是悦乐书的第215次更新,第228篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第83题(顺位题号是400).找到无限整数序列的第n个数字1,2,3,4,5,6,7,8 ...

  8. LeetCode算法题-Reverse Linked List(Java实现)

    这是悦乐书的第192次更新,第195篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第51题(顺位题号是206).反转单链表.例如: 输入:1-> 2-> 3- ...

  9. LeetCode算法题-Convert a Number to Hexadecimal(Java实现)

    这是悦乐书的第219次更新,第231篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第86题(顺位题号是405).给定一个整数,写一个算法将其转换为十六进制.对于负整数,使 ...

最新文章

  1. mysql case when 去重_【Mysql】 case ... when ... 用法
  2. elasticsearch7.x源码编译
  3. Notepad++ 列编辑操作实例二则
  4. Cortex M3寄存器组
  5. Android 编译系统分析(三)
  6. 计算机应用基础寒假作业,计算机应用基础理论试卷寒假作业.doc
  7. MySQL执行计划extra中的using index 和 using where using index 的区别
  8. 关于c:if没有c:else解决方案
  9. 出现( linker command failed with exit code 1)错误总结
  10. HDOJ 1166 HDU 1166 敌兵布阵 ACM 1166 IN HDU
  11. php 电梯程序设计,plc在电梯自动控制中的应用编程实例
  12. Scrapy 爬取阳光热线问政平台存储为json 文件(使用 CrawlSpider)
  13. SphereEx张亮:“开源和商业化不能形成对立”
  14. URAL 1741 Communication Fiend
  15. Python+Vue计算机毕业设计酒店管理系统(前台后台)i2agu(源码+程序+LW+部署)
  16. 怎么判断两个多项式互素_关于两个多元多项式互素问题
  17. Foxdisk11-小字库显示汉字2
  18. 医院选址c语言课程设计,通信学院2012届本科毕业设计选题结果(学生)2.xls
  19. 锐捷睿易:扩大DHCP掩码导致AP不上线问题
  20. 2023拼多多店铺分类id

热门文章

  1. 强化学习重点文献汇总
  2. js案例:5秒后自动跳转
  3. 基于Arduino Uno的RFID门禁
  4. PADS Router 布线前Layout设置和布线
  5. linux中用vi读文件夹,linux下vi与vim编辑器的简单区别及VI详细使用方法
  6. 以太坊(ETH)简单的交易
  7. 互联网怎么赚钱?放弃固有思维才有希望!
  8. 基于JAVA古玩玉器交易系统计算机毕业设计源码+数据库+lw文档+系统+部署
  9. STM32 超声波模块测距
  10. 关于if if和if elseif的区别