1、快速查找一个数组中的某个值 可用二分查找,注意:二分查找区间的开闭。
以后大家只要看到面试题里给出的数组是有序数组,都可以想一想是否可以使用二分法。
同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的。
- 给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
例如:输入: nums = [1,2,3,4,5,6,7], k = 3
向右轮转 1 步: [7,1,2,3,4,5,6]。向右轮转 2 步: [6,7,1,2,3,4,5]。
向右轮转 3 步: [5,6,7,1,2,3,4]
方法一:可以使用额外的数组来将每个元素放至正确的位置。用 n 表示数组的长度,遍历原数组,将原数组下标为 i 的元素放至新数组下标为 (i+k)%n 的位置,最后将新数组拷贝至原数组即可..newArr[(i + k) % n] = nums[i];
方法二:三次反转。翻转的下标分界点为n-k而不是k了。为防止k>数组长度n。令k=k%n;
方法三:切片法。或者说新建一个vector<int>,把元素按相应位置放入vector。,先放后面从n-k开始的元素,然后放前面的元素。如果k>n 则令k等于k%n
3、字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。:
方法一:三次reverse。
方法二:int k=s.size()-n;然后相当于右旋转k。用(i+k)%s.size();
方法三:切片法,
切片法:输入s=”abcdefg”,n=2;
切片:s[n:]=”cdefg”;s[:n]=”ab”; 返回s[n:]+s[n:]=”cdefgab”;
方法四:可以建一个vector<char>str;分别把s中后一部分和前一部分放进去,然后把vector转成字符串;
方法五:return s.substr(n, s.size()-n) + s.substr(0, n);
4、定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
方法一:定义两个栈,一个普通的栈a,另一个用栈b来维持剩余栈中最小数,即递减的栈(非严格降序),进栈时,若x小于等于b栈顶元素,则入栈。出栈时,若a栈顶元素等于b栈元素,则b也出栈。b栈顶元素永远是剩余元素中最小的。
5请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
方法一:计算空格数量n; s.resize()重新定义数组长度。倒序遍历赋值,遇到空格就换成“%20”;注意设置两个下标,一个原数组长度最后一个位置遍历,一个新长度从最后一个位置遍历,减减
方法二:计算原数组长度,创建新数组长度为原来三倍,从头遍历原数组,并为新数组赋值,遇到空格就替换成“%20”。并用size++作为下标计算新数组长度。最后返回新数组前size个字符作为字符串。
方法三:创建vector<char>str;正面遍历原字符串,遇到空格就放入‘%’ ‘2’ ‘0’然后把vector中字符拼接成字符串
- 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。(必须在不复制数组的情况下原地对数组进行操作。)
双指针法,遇到非零就从头赋值,复制完后面都设为零
或创建一个vector<int>,把非零元素放入,然后放零
7、给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
方法一:同时遍历两个链表,逐位计算它们的和,并与当前位置的进位值相加。具体而言,如果当前两个链表处相应位置的数字为 n1,n2,进位值为carry,则它们的和为 n1+n2+carry;其中,答案链表处相应位置的数字为n1+n2+carry)%10,而新的进位值为
(n1+n2+carry)/10.。如果两个链表的长度不同,则可以认为长度短的链表的后面有若干个 0。
8、在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
方法一:排序,然后找nums[i]==nums[i-1];
方法二。放在集合里,判断集合中是否出现过。出现过 就输出,否则就输入到集合。
- 统计一个数字在排序数组中出现的次数。:
方法一:先排序,然后遍历统计。方法二:二分查找。
10、一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
方法一:二分查找,有序无重复数组查找首先先到二分查找。把数组分成两组,左边数组下标与数值相等,右边一组不相等,找出右边数组的第一个元素的下标。需要一直二分到最后,返回ri或者le
11、在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
方法一:用unordered_map<char,int>map统计每个字母出现的次数,然后从头遍历,找第一个map[char]==1的元素。
数字转成字母。直接加‘a’。如5+‘a’将数值转成字符串型可用to_string()函数
- 给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
方法一:先统计长度,然后求中间长度count。然后count--遍历。。方法二:也可以把每个节点放入vector中,然后取中间的。
- 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
方法:设置两个指针,一个快一个慢,先让快指针走n步,然后再走1步;
然后让快指针和慢指针一起走,到快指针为NULL 的时候,slow->next就是要删除的结点。
- 二叉树的层序遍历:用queue队列存放每个结点。求每一层的结点个数size。然后遍历取出这些节点,同时把每个结点的左右子树放进队列。
- 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
方法一:奇数 是直接放进去,偶数则先翻转在放入大vector
- 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
方法一:滑动窗口法,int r;for(int i=0;i<s.size();i++) 用set记录r到i窗口中的字符。内部用while。出现重复的就跳出while。记录最大长度;
17、给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的 子串 。
方法一:滑动窗口。由于排列不会改变字符串中每个字符的个数,所以只有当两个字符串每个字符的个数均相等时,一个字符串才是另一个字符串的排列。用两个vector<int>c1(26),c2(26)记录s1长度字符创的个数。维护s1长度窗口内的字符个数,若c1==c2则返回true。注意 不能直接用int [].因为vector重载了==而int[]数组不能直接用==比较。
18、假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
方法1:设置一个minx记录prices遍历过去的最小的价格,result=max(result, prices[i]-minx);
minx的初始值为prices[0];或INT_MAX;
方法2:动态规划。dp[i]即前i日最大利润=max(前(i−1)日最大利润,第i日价格−前i日最低价格)
19:给你两个非负整数 low 和 high 。请你返回 low 和 high 之间(包括二者)奇数的数目。
方法:区间内数字的个数除2,若首尾有奇数则再加上1。
- 给定一个长度为 n 的整数数组height。有n条垂线,第 i 条线的两个端点是(i, 0)和(i, height[i])。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
方法:双指针法,双指针为边界,计算每个边界的面积,保留最大值,每次移动height较小的一端。从两端向内部靠拢。。最开始两端为边界表示内部所有位置都可以当边界。
- 编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量)。
方法:我们可以直接循环检查给定整数 nn 的二进制位的每一位是否为1具体代码中,当检查第 i 位时,我们可以让n 与 2^i进行与运算,当且仅当 n 的第 i 位为 1 时,运算结果不为 0。for (int i = 0; i < 32; i++) { if (n & (1 << i)) { ret++; } }
- 给你一个整数 n,请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。
方法:要求一个整数的每一位的时候可以采用:对10取余,然后将那个数除10.不断循环。
while(x){int wei=x%10; ji*=wei;he+=wei; x=x/10; }
注意:要将每个数拼成整数时,可采用:int sum=0;sum=sum*10+x;
- 输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。。方法1、设置一个count为最小整数,用来记录过程中讲过的最大的,设置一个sum+=num[i];当sum
<0时。sum=0;
24、在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
设 f(i, j)f(i,j) 为从棋盘左上角走至单元格 (i ,j)(i,j) 的礼物最大累计价值,易得到以下递推关系:f(i,j) 等于 f(i,j−1) 和 f(i−1,j) 中的较大值加上当前单元格礼物价值 grid(i,j) 。f(i,j)=max[f(i,j−1),f(i−1,j)]+grid(i,j)。边缘初始化是累加
给定由一些正数(代表长度)组成的数组 nums ,返回 由其中三个长度组成的、面积不为零的三角形的最大周长 。如果不能形成任何面积不为零的三角形,返回 0。
方法:先排序。我们可以选择枚举三角形的最长边 cc,而从贪心的角度考虑,我们一定是选「小于 c 的最大的两个数」作为边长 a 和 b,此时最有可能满足 a+b>c,使得三条边能够组成一个三角形,且此时的三角形的周长是最大的。
给你两个整数 x 和 y ,表示你在一个笛卡尔坐标系下的 (x, y) 处。同时,在同一个坐标系下给你一个数组 points ,其中 points[i] = [ai, bi] 表示在 (ai, bi) 处有一个点。当一个点与你所在的位置有相同的 x 坐标或者相同的 y 坐标时,我们称这个点是 有效的 。请返回距离你当前位置 曼哈顿距离 最近的 有效 点的下标(下标从 0 开始)。如果有多个最近的有效点,请返回下标 最小 的一个。如果没有有效点,请返回 -1 。
方法1:可用unordered_map<int,vector<int>>map;记录有效点及下标。转成vector后排序,按距离由小到大排序,然后染回result[0].second[0];如果没有有效点,即map.size()==0.return -1;
方法2:计算每个符合条件的坐标距离,并记录下标,当遇到更小的距离时才替换记录的下标,否则不改变记录的下标
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
方法:先通过取余把每个数字符放到vector中,然后翻转。通过动态规划求方法种树。
考虑情况:第i个字符单独翻译,第i和第i-1个字符一起翻译。f(i)=f(i−1)+f(i−2)[i−1≥0,10≤x≤25]
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
方法:
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
方法:遍历A每个结点,当A中结点与B第一个节点值相等的时候,调用递归函数判断B是否与A以当前为根结点子树相等;
30、21. 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
方法1:递归:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if(list1==nullptr)return list2;
if(list2==nullptr)return list1;
if(list1->val<list2->val){
list1->next=mergeTwoLists(list1->next,list2);
return list1;
}
else{
list2->next=mergeTwoLists(list1,list2->next);
return list2;
}
}
方法二:迭代:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* preHead = new ListNode(-1);
ListNode* prev = preHead;
while (l1 != nullptr && l2 != nullptr) {
if (l1->val < l2->val) {
prev->next = l1;
l1 = l1->next;
} else {
prev->next = l2;
l2 = l2->next;
}
prev = prev->next;
}
// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
prev->next = l1 == nullptr ? l2 : l1;
return preHead->next;
}
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
方法:这个题目无重复,若有重复记得去重,去重有两种方式。还分同一层去重和同一分支去重。看代码随想录。
输入两个链表,找出它们的第一个公共节点。
方法:如果两个链表中有个节点相同,则从结点开始后面的每个都相同;因此计算每个链表的长度。找出长的一方,先走几步,使两个链表长度相同,相同的起点,然后同时遍历两个链表,看是否有相同的点。
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。
方法1、:申请一个vector来操作。
方法2:考虑定义双指针 i , j 分列数组左右两端,循环执行:
指针 i 从左向右寻找偶数;
指针 j 从右向左寻找奇数;
vector<int> exchange(vector<int>& nums) {
int i=0;
int j=nums.size()-1;
while(i<j){
while(i<j&&nums[i]%2==1)i++;
while(i<j&&nums[j]%2==0)j--;
if(i<j&&nums[i]%2==0&&nums[j]%2==1){
swap(nums[i],nums[j]);
i++;j--;
}
}
return nums;
}数 nums[i]nums[i] 和 奇数 nums[j]nums[j] 交换。
34、剑指 Offer 57. 和为s的两个数字
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可
方法一:创建一个set或unordered_set。判断里面是否有target-nums[i]。如果有,则输出nums[i]和target-nums[i]。否则把nums[i]加入。
方法二:初始化: 双指针 i, j分别指向数组 numsnums 的左右两端 (俗称对撞双指针)。
循环搜索: 当双指针相遇时跳出;
计算和 s = nums[i] + nums[j]s=nums[i]+nums[j] ;
若 s > target ,则指针 j 向左移动,即执行 j = j - 1 ;
若 s < target ,则指针 i 向右移动,即执行 i=i+1 ;
若 s = target ,立即返回数组 [nums[i], nums[j]] ;
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。
方法:自己复习思路。
给定一个字符串 s ,通过将字符串 s 中的每个字母转变大小写,我们可以获得一个新的字符串。
输入:s = "a1b2"输出:["a1b2", "a1B2", "A1b2", "A1B2"]
方法:大写转小写:c=tolower(s[i]);小写转大写:c=toupper(s[i]);
字符串大小写转换:transform(str.begin(),str.end(),str.begin(),::tolower);注意是tolower或toupper。不带括号。
大写变小写、小写变大写 : 字符 ^= 32;
大写变小写、小写变小写 : 字符 |= 32;
小写变大写、大写变大写 : 字符 &= -33;
vector<string>result;
string str;
void backtracking(string &s,int index){
if(str.size()==s.size()){
result.emplace_back(str);
return ;
}
if(index==s.size())return;
for(int i=index;i<s.size();i++){
if((s[i]>='A'&&s[i]<='Z')||(s[i]>='a'&&s[i]<='z')){
str.push_back(s[i]);
backtracking(s,i+1);
str.pop_back();
str.push_back(s[i]^(1<<5));转换大小写
backtracking(s,i+1);
str.pop_back();
}
else{
str.push_back(s[i]);
backtracking(s,i+1);
str.pop_back();
}
}
}
------------------------------------------------------------------------------------------------------------------------------
37、198. 打家劫舍。你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);考虑偷i和不考虑偷i。注意初始化
给定一个三角形 triangle ,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。
int n=triangle.size();
vector<vector<int>>dp(n,vector<int>(n));
dp[0][0]=triangle[0][0];
for(int i=1;i<n;i++){
for(int j=0;j<=i;j++){
if(j==0)dp[i][j]=dp[i-1][j]+triangle[i][j];
else if(j==i)dp[i][j]=dp[i-1][j-1]+triangle[i][j];
else {
dp[i][j]=min(dp[i-1][j],dp[i-1][j-1])+triangle[i][j];
}
}
}
return*min_element(dp[n-1].begin(),dp[n-1].end());
39、231. 2 的幂
给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回true;否则,返回false。
将n的二进制表示中最低位的那个1提取出来,再判断剩余的数值是否为0即可
如果n是正整数并且n&(n-1)=0,那么n就是2的幂。如果n是正整数并且n&(-n)=n,那么n就是2的幂
return n>0&&(n&(n-1))==0;。
40、191. 位1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量)for(int i=0;i<32;i++){if(n&(1<<i))count++;}.<<左移位运算符1移几位就是2的几次方
给你二叉树的根节点root和一个整数目标和targetSum,找出所有从根节点到叶子节点路径总和等于给定目标和的路径。
vector<vector<int>>result;
vector<int>path;
void backtracking(TreeNode*root,int sum,int target){
if(sum==target&&root->left==nullptr&&root->right==nullptr){
result.push_back(path);
return ;
}
if(root->left){
sum+=root->left->val;
path.push_back(root->left->val);
backtracking(root->left,sum,target);
sum-=root->left->val;
path.pop_back();
}
if(root->right){
sum+=root->right->val;
path.push_back(root->right->val);
backtracking(root->right,sum,target);
sum-=root->right->val;
path.pop_back();
}
}
vector<vector<int>> pathSum(TreeNode* root, int target) {
if(root==nullptr)return result;
int sum=0;
if(root){
sum+=root->val;
path.push_back(root->val);
backtracking(root,sum,target);
sum-=root->val;
path.pop_back();
}
return result;
}
------------------------------------------------------------------------------------------------------------------------------
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
Node* treeToDoublyList(Node* root) {
if(root == nullptr) return nullptr;
dfs(root);
head->left = pre;
pre->right = head;
return head;
}
private:
Node *pre, *head;
void dfs(Node* cur) {
if(cur == nullptr) return;
dfs(cur->left);
if(pre != nullptr) pre->right = cur;
else head = cur;
cur->left = pre;
pre = cur;
dfs(cur->right);
}
43、给定一棵二叉搜索树,请找出其中第 k 大的节点的值。方法:中序遍历放入数组,数组为单调递增的。
搜索二叉树中序遍历到数组是单调递增的
44、207. 课程表
你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。方法:入度:指向它的。出度:它指向的。看leetcode视频。多复习
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>>edge;
vector<int>indg;
indg.resize(numCourses);
edge.resize(numCourses);
for(int i=0;i<prerequisites.size();i++){
edge[prerequisites[i][1]].push_back(prerequisites[i][0]);
indg[prerequisites[i][0]]++;
}
queue<int>que;
for(int i=0;i<numCourses;i++){
if(indg[i]==0)que.push(i);
}
int ans=0;
while(!que.empty()){
ans++;
int q=que.front();
que.pop();
for(int v:edge[q]){
indg[v]--;
if(indg[v]==0)que.push(v);
}
}
return ans==numCourses;
}
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
int row;
int col;
bool digui(vector<vector<char>>& board, string word,int i,int j,int k){
if(i<0||j<0||i>=row||j>=col||board[i][j]!=word[k])return false;
if(k==word.size()-1)return true;
board[i][j]='\0';
bool res=digui(board,word,i-1,j,k+1)||digui(board,word,i+1,j,k+1)||digui(board,word,i,j-1,k+1)||digui(board,word,i,j+1,k+1);
board[i][j]=word[k];
return res;
}
bool exist(vector<vector<char>>& board, string word) {
row=board.size();
col=board[0].size();
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
if(digui(board,word,i,j,0))return true;
}
}
return false;
}
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
int ans=0;
int movingCount(int m, int n, int k) {
vector<vector<bool>>path(m,vector<bool>(n,false));
digui(0,0,m,n,k,path);
return ans;
}
void digui(int i,int j,int m,int n,int k,vector<vector<bool>>&path){
if(i<0||j<0||i>=m||j>=n||path[i][j])return;
path[i][j]=true;
if(i%10+j%10+i/10+j/10>k)return;
ans++;
digui(i-1,j,m,n,k,path);
digui(i+1,j,m,n,k,path);
digui(i,j-1,m,n,k,path);
digui(i,j+1,m,n,k,path);
}
47、704. 二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。方法:有序无重复数组找首先考虑二分查找
int search(vector<int>& nums, int target) {
int le=0;
int ri=nums.size()-1;
while(le<=ri){
int mid=le+(ri-le)/2;
if(target>nums[mid]){
le=mid+1;
}
else if(nums[mid]>target){
ri=mid-1;
}
else{
return mid;
}
}
return -1;
}
48、278. 第一个错误的版本
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
方法:先考虑二分查找
int firstBadVersion(int n) {
int l=1;int r=n;
while(l<=r){
int mid=l+(r-l)/2;
if(isBadVersion(mid)){
if(isBadVersion(mid-1)==false)return mid;
r=mid-1;
}
else{
if(isBadVersion(mid+1))return mid+1;
l=mid+1;
}
}
return -1;
}
输入一个非负整数数组,把数组里所有数字拼接起来排成 个数,打印能拼接出的所有数字中最小的一个。
输入: [3,30,34,5,9]输出: "3033459"
static bool cmp(string &a,string &b){
return ((a+b)<(b+a));
}
string minNumber(vector<int>& nums) {
int n=nums.size();
vector<string>str(n);
for(int i=0;i<n;i++){
str[i]=to_string(nums[i]);
}
sort(str.begin(),str.end(),cmp);
string s="";
for(int i=0;i<n;i++){
s+=str[i];
}
return s;
}
------------------------------------------------------------------------------------------------------------------------------------
从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
充要条件:最大值与最小值的差小于5。除0(大小王)外不能重复。用set去重
bool isStraight(vector<int>& nums) {
unordered_set<int>set;
int n=INT_MAX;
int x=INT_MIN;
for(int i=0;i<nums.size();i++){
if(nums[i]!=0&&set.find(nums[i])!=set.end())return false;
else{
set.insert(nums[i]);
}
if(nums[i]!=0)n=min(n,nums[i]);
x=max(x,nums[i]);
}
if(x-n<5)return true;
return false;
}
第一个错版本后面都是错的,你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错,找出第一个出错的下标。尽量少调用api。
方法:首先考虑二分查找
int firstBadVersion(int n) {
int le=1;
int ri=n;
while(le<=ri){
int mid=le+(ri-le)/2;
if(isBadVersion(mid)){
if(isBadVersion(mid-1)==false)return mid;
else{
ri=mid-1;
}
}
else{
if(isBadVersion(mid+1))return mid+1;
else{
le=mid+1;
}
}
}
return ri;
}
52、35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1, ans = n;
while (left <= right) {
int mid = ((right - left) >> 1) + left;
if (target <= nums[mid]) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
53、977. 有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
方法一:按平方大小排序。改sort规则。方法二:平方最大的肯定在数组两端,设置容器ans。倒序插入。双指针遍历数组两端。
static bool cmp(int &a,int &b){
return a*a<b*b;
}
vector<int> sortedSquares(vector<int>& nums) {
sort(nums.begin(),nums.end(),cmp);
for(int i=0;i<nums.size();i++){
nums[i]=nums[i]*nums[i];
}
return nums;
}
static bool cmp(int &a,int &b){
return a*a<b*b;
}
vector<int> sortedSquares(vector<int>& nums) {
sort(nums.begin(),nums.end(),cmp);
for(int i=0;i<nums.size();i++){
nums[i]=nums[i]*nums[i];
}
return nums;
}
vector<int> sortedSquares(vector<int>& nums) {
int i=0;int j=nums.size()-1;
vector<int>ans(nums.size());
int k=nums.size()-1;
for(;i<=j;){
if((nums[i]*nums[i])>nums[j]*nums[j]){
ans[k--]=nums[i]*nums[i];
i++;
}
else{
ans[k--]=nums[j]*nums[j];
j--;
}
}
return ans;
- 快速排序
int getStandard(int array[], int i, int j) {
// 基准数据
int key = array[i];
while (i < j) {
// 因为默认基准是从左边开始,所以从右边开始比较
// 当队尾的元素大于等于基准数据 时,就一直向前挪动 j 指针
while (i < j && array[j] >= key) {
j--;
}
// 当找到比 array[i] 小的时,就把后面的值 array[j] 赋给它
if (i < j) {
array[i] = array[j];
}
// 当队首元素小于等于基准数据 时,就一直向后挪动 i 指针
while (i < j && array[i] <= key) {
i++;
}
// 当找到比 array[j] 大的时,就把前面的值 array[i] 赋给它
if (i < j) {
array[j] = array[i];
}
}
// 跳出循环时 i 和 j 相等,此时的 i 或 j 就是 key 的正确索引位置
// 把基准数据赋给正确位置
array[i] = key;
return i;
}
void QuickSort(int array[], int low, int high) {
// 开始默认基准为 low
if (low < high) {
// 分段位置下标
int standard = getStandard(array, low, high);
// 递归调用排序
// 左边排序
QuickSort(array, low, standard - 1);
// 右边排序
QuickSort(array, standard + 1, high);
}
}
- 冒泡排序
for (i = 0; i<N - 1; i++) { //控制n-1趟冒泡
for (j = 0; j<N - 1 - i; j++)
{
if (a[j]>a[j + 1]) { //比较相邻的两个元素
int tmp; //临时变量
tmp = a[j]; //交换
a[j] = a[j + 1];
a[j + 1] = tmp;
}
}
}