索引
- 1. n个人围成圈,依次报数,每次数到m的人淘汰,求最后剩下的人
- 2. [整数反转](https://leetcode-cn.com/problems/reverse-integer/)
- 3.[回文数](https://leetcode-cn.com/problems/palindrome-number/)
- 4. [两数相加](https://leetcode-cn.com/problems/add-two-numbers/)
- 5. [无重复字符的最长子串](https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/)
- 6. 输入若干个字符串,统计其中每个字符串的出现次数
- 取两个递增链表的交集
- 8. [面试题13. 机器人的运动范围](https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/)
- 9. [最长回文子串](https://leetcode-cn.com/problems/longest-palindromic-substring/)
- 10. [全排列](https://leetcode-cn.com/problems/permutations/)
- 11. 走迷宫
1. n个人围成圈,依次报数,每次数到m的人淘汰,求最后剩下的人
双向链表实现:
#include <cstdio>
#include <iostream>
using namespace std;
const int MAX = 100 + 10;
int a[MAX],b[MAX];
int main()
{
int m,n;
cin >> n >> m;
for (int i = 1; i <= n-1; i++) a[i]=i+1,b[i]=i-1;
a[n]=1,b[1]=n;
int c=1;
for (int i = 1; i <= n-1; i++)
{
for(int t=1;t<=m-1;t++) c=a[c];
//c被淘汰
printf("第%d个淘汰:%d\n", i , c );
b[a[c]]=b[c]; //c下一个人的上一个(原本是c)指向c的上一个
a[b[c]]=a[c]; //c上一个人的下一个(原本是c)指向c的下一个
c=a[c]; //从c的下一个人开始
}
cout<<"最后剩下了:"<<c<<endl;
cin>>n; //只是为了暂停
return 0;
}
2. 整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
解题思路
一开始我还无耻地试图用try catch解决溢出问题:只要error直接return 0
结果发现leetcode的编译器不吃这套,照样runtime error
那么只好中规中矩地写了,检验溢出的方法就是先定义一个MAX_INT/10的值,反转后每次加新的值上去之前先除10看看会不会溢出(如果不除10直接加上去就error了)
先分离符号位,避免不要的麻烦,最后再加上就是了。
跑个while循环计算一下有几位。
如果是个个位数就直接返回,省的跑一遍
还有一个要注意,如果是-231次方,去掉符号位的时候会直接溢出
然后循环就一位一位地剥离,%10(取最后一位数字), /=10(去掉最后一位数字),乘以相应的位数,加到ans里(加之前先把二者除10加一下看看会不会超过maxn)
代码
#include <cmath>
class Solution {
public:
const int maxn=214748365; //max_int / 10 ,构建的数除以10必须小于这个数,否则溢出
const int pow[11]={0,1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
int reverse(int x) {
if(abs(x)<10) return x;
if(x==-2147483648) return 0;
int ans = 0,n = 0,t = 0, flag = x/abs(x);
x = abs(x);
int y = x;
while(y) //数x的位数
{
y/=10;
n++;
}
for(int i=n;i>=1;i--)
{
t = x % 10;
if(t*pow[i-1] + ans/10 >= maxn) return 0;
ans += t*pow[i];
x/=10;
}
return ans*flag;
}
};
3.回文数
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
- 转字符串解法:
#include <string>
using namespace std;
class Solution {
public:
bool isPalindrome(int x) {
if(x<0) return false;
if(x>=0 && x<10) return true;
string s = to_string(x);
for(int i=0;i<=s.length()/2;i++)
if(s[i]!=s[s.length-1-i]) return false;
return true;
}
};
- 纯数字解
class Solution {
public:
const int pow[11]={0,1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
bool isPalindrome(int x) {
if(x<0) return false;
if(x>=0 && x<10) return true;
int y=x,n=0;
while(y){ //数y的位数
y/=10;
n++;
}
for(int i=1;i<=n;i++)
if( (x/pow[i]) % 10 != (x/pow[n-i+1])%10) return false;
return true;
}
};
4. 两数相加
给出两个非空的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储一位数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
// Definition for singly-linked list.
#include <string>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
//ac
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2)
{
string s1,s2,a,b; //a > b
while(l1 != NULL)
{
s1.append(to_string(l1->val));
l1=l1->next;
}
while(l2 != NULL)
{
s2.append(to_string(l2->val));
l2=l2->next;
}
if(s1.length()>s2.length()) //保证a的长度比b长
{
a=s1;
b=s2;
}
else{
a=s2;
b=s1;
}
while(a.length()>b.length()) //给b后面补0补到和a一样的位置
b.append("0");
ListNode *ans=new ListNode(0);
ListNode *t = ans;
int tmp,add=0;
for(int i=0;i<a.length();i++)
{
tmp=a[i]-'0' + b[i]-'0' + add;
add=tmp/10; //add保存是否进位
tmp %= 10;
t->val=tmp;
if(i<a.length()-1)
{
t->next = new ListNode(0);
t=t->next;
}
}
if(add) t->next=new ListNode(add);
return ans;
}
};
5. 无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
滑动窗口法:
对于字符串s , 我们维护一个长度为width = r - l +1的子字符串,称之为滑动窗口,初始l=0,r=0,width=1,初始窗口是s[0]。每次从右边拉一个字符进来,如果此时窗口中有重复字符,那么从左端去掉一个字符: l++
,如果还是重复,那么一直去到无重复字符为止,以上述规则跑完全程,始终保持窗口内无重复,其间每次操作检测窗口长度维护一个最大值。即可以O(n)的复杂度完成
#include <string>
using namespace std;
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s=="") return 0;
int width;
int ans = 0;
int l=0,r=0;
string w;
for( ; r < s.length() ; r++)
{
width = r - l + 1;
if(width>ans) ans=width;
w = s.substr(l,width);
for(int i=0;i<w.length();i++)
if(r+1<s.length() && w[i]==s[r+1])
{
while(s[l]!=s[r+1]) l++; //找到与s[r+1](即将移入左端的字符)重复的字符位置
l++; //左端移除重复的字符
break;
}
}
return ans;
}
};
6. 输入若干个字符串,统计其中每个字符串的出现次数
- 解题思路
我们使用priority_queue
来维护一个字典序排序的string
堆,就可以在线性时间内完成全部的统计工作
#include <iostream>
#include <queue>
using namespace std;
int main()
{
priority_queue<string> heap;
string s;
while (true)
{
cin >> s;
if (s == "0") break;
heap.push(s);
}
string last=heap.top();
int count = 1;
heap.pop();
while (!heap.empty())
{
if (heap.top() == last) count++;
else
{
cout << last << ":" << count << endl;
count = 1;
last = heap.top();
}
heap.pop();
}
cout << last << ":" << count << endl;
}
#include <stdlib.h>
#include <stdio.h>
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
void push_back(int data) //在尾部添加元素
{
ListNode* p = this;
while (p->next != NULL) p = p->next;
p->next = new ListNode(data);
}
};
int main()
{
ListNode* A = new ListNode(1);
ListNode* B = new ListNode(2);
ListNode* pA = A;
ListNode* pB = B;
ListNode* ans=new ListNode(0); int flag = 0;
while (pA != NULL && pB != NULL)
{
while (pA != NULL && pA->val < pB->val) pA = pA->next;
if (pA->val == pB->val)
{
if (!flag) { ans->val=pA->val; flag = 1; }
else ans->push_back(pA->val);
pA = pA->next;
}
pB = pB->next;
}
return;
}
8. 面试题13. 机器人的运动范围
地上有一个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。请问该机器人能够到达多少个格子?
输入:m = 2, n = 3, k = 1 输出:3
输入:m = 3, n = 1, k = 0 输出:1
提示: 1 <= n,m <= 100 0 <= k <= 20
直接遍历每个格子,位数之和不能大于k那也就是
条件1: i % 10 + i / 10 + j % 10 + j / 10 <= k
注意机器人只能四个方向移动,那么第i,j个格子能到达的必要条件还有一个:
条件2: map[ i - 1][ j ] || map[ i ][ j - 1]
(从小到大遍历,只能从上面或者左边来)
满足两个条件,即可标记 map[i][j] = 1
然后答案+1
注意初始条件:map[0][0] = 1
,因此答案最小是1
class Solution {
public:
int movingCount(int m, int n, int k) {
int count = 1;
int map[100][100]= { 0 };
map[0][0] = 1; //第一个格子必定可以到
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
if(i==0&&j==0) continue;
if(i%10 + i/10 + j%10 + j/10 <= k )
if((i>0 && map[i-1][j]) || (j>0 && map[i][j-1]))
{
map[i][j]=1;
count++;
}
}
return count;
}
};
9. 最长回文子串
#include <string>
using namespace std;
class Solution {
public:
string longestPalindrome(string s) {
string ans(" ");
ans[0] = s[0];
for(int i=0;i<s.length();i++)
{
for(int j=s.length()-1 ; j>i ; j--)
{
if(s[i] == s[j])
{
int flag = 1;
for(int r=i,l=j; r<l ; r++,l--)
if(s[r]!=s[l]){flag = 0 ; break;}
if(flag)
{
if(ans.length() < j - i + 1 ) //如果比已有的回文子串更长
ans = s.substr(i,j-i+1);
break;
}
}
}
}
return ans;
}
};
10. 全排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
递归回溯,每个位置尝试填入原排列1~N位置上的数字,填了一次就标记,返回时再把标记擦除。同时传递一个一维向量,保存每一次递归构造的排列,当digit = N
时(已经构造到最后一位数)放入保存答案的二维向量中即可。
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<int> tmp;
memset(vis,0,sizeof(vis));
dfs(nums.size(),1,tmp,nums);
return seq;
}
private:
vector<vector<int>> seq;
int vis[1000];
void dfs(int n,int digit,vector<int> tmp,vector<int> & nums)
{
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
tmp.emplace_back(nums[i-1]);
vis[i] = 1;
if(digit < n)
dfs(n, digit + 1, tmp,nums);
else {
seq.emplace_back(tmp);
vis[i] = 0;
return;
}
tmp.pop_back();
vis[i] = 0;
}
}
}
};
11. 走迷宫
输入一个用01矩阵表示的迷宫,0表示地面,1表示障碍物。起点为左上顶点,终点为右下顶点。输出最少步数或者无解。
方法1:DFS
#include <stdio.h>
#define MAXN 100
int map[MAXN][MAXN];
int vis[MAXN][MAXN];
int m,n;
int ans;
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
void dfs(int x,int y,int dep)
{
printf("(%d , %d)\n", x, y);
if (x == m && y == n)
{
if (dep < ans) ans = dep;
return;
}
vis[x][y] = 1;
for (int i = 0; i < 4; i++)
{
int xx = x + dx[i], yy = y + dy[i];
if (xx >= 1 && yy >= 1 && xx <= m && yy <= n && vis[xx][yy]==0 && map[xx][yy] == 0)
dfs(xx, yy, dep + 1);
}
vis[x][y] = 0;
}
void init()
{
scanf_s("%d%d", &m,&n);
ans = m * n;
for(int i = 1; i <= m;i++)
for (int j = 1; j <= n; j++)
{
scanf_s("%d", &map[i][j]); //0表示可以走,1表示不能走
vis[i][j] = 0;
}
}
int main()
{
init();
dfs(1,1,0);
if (ans == m * n) printf("No Solution.");
else printf("Ans = %d", ans);
getchar();getchar();
return 0;
}