其他算法题目
数组中重复的数据
解题思路:
遍历数组,假如当前数字nums[i] = x,则把下标为x-1的数字变成负数 (nums[x-1] = -nums[x-1])。
继续遍历,若第二次遇到x的时候,我们去查找x-1位置的数字是否为负数,是的话则说明之前遇到过了x,把它加入答案中。
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
vector<int>res;
for(int x:nums){
if(nums[abs(x)-1]<0)res.push_back(abs(x));
else{
nums[abs(x)-1]*=-1;
}
}
return res;
}
};
将整数转换为两个无零整数的和
class Solution {
public:
//双指针
bool isHave0(int x){
while(x>0){
if(x%10==0)return true;
x/=10;
}
return false;
}
vector<int> getNoZeroIntegers(int n) {
int left=1;
vector<int>ans;
while(left<=(n>>1)){
if(isHave0(left)||isHave0(n-left)){
left++;
}else{
ans.push_back(left);
ans.push_back(n-left);
return ans;
}
}
return ans;
}
};
矩形重叠
解题思路:
矩形如果不重叠,从x轴和y轴上看两个矩形就变成了两条线段,这两条线段肯定是不相交的,也就是说左边的矩形的最右边小于右边矩形的最左边 。
class Solution {
public:
bool isRectangleOverlap(vector<int>& rec1, vector<int>& rec2) {
//只有在x轴上和y轴上的投影同时是一条线段,两个矩形才重叠
int x10=rec1[0];
int x11=rec1[2];
int x20=rec2[0];
int x21=rec2[2];
if(x21<=x10||x20>=x11)return false;
int y10=rec1[1];
int y11=rec1[3];
int y20=rec2[1];
int y21=rec2[3];
if(y21<=y10||y20>=y11)return false;
return true;
}
};
岛屿的周长
class Solution {
public int islandPerimeter(int[][] grid) {
int ans=0;
for(int row=0;row<grid.length;++row){
for(int col=0;col<grid[0].length;++col){
if(grid[row][col]==1){
if(row==0){
ans++;
}
if(row>0&&grid[row-1][col]==0){
ans++;
}
if(row==grid.length-1){
ans++;
}
if(row<grid.length-1&&grid[row+1][col]==0){
ans++;
}
if(col==0){
ans++;
}
if(col>0&&grid[row][col-1]==0){
ans++;
}
if(col==grid[0].length-1){
ans++;
}
if(col<grid[0].length-1&&grid[row][col+1]==0){
ans++;
}
}
}
}
return ans;
}
}
下载插件
说明:
暴力递归答案是正确的,但是运行超时
动态规划没改对
最后尝试了打表法,用暴力递归跑一些样例,从中总结出规律,得到复杂度
O
(
l
o
g
N
)
O(logN)
O(logN) 。
class Solution {
//暴力递归
//当前还剩下rest个插件,当前来到了第index分钟,当前可以下载的插件数量
public int process(int rest,int index,int num){
if(rest<=0){//插件已经全部下载完毕
return index-1;
}
//插件尚未下载完毕
if(num>=rest){
return index;
}
//第index分钟用来带宽加倍
//第index分钟用来下载插件
return Math.min(process(rest,index+1,num*2),process(rest-num,index+1,num));
}
public int DP(int n){
//index: 1~n+1 num :0~n*2 rest: 0~n
int[][][] dp=new int[n+2][n*2+1][n+1];
for(int level=1;level<n+1;++level){
for(int row=0;row<=n*2;++row){
dp[level][row][0]=level-1;
}
for(int row=n*2;row>=0;--row){
for(int col=1;col<=n;++col){
if(row>=col){
dp[level][row][col]=level;
}else{
dp[level][row][col]=Math.min(row*2<=n*2?dp[level+1][row*2][col]:Integer.MAX_VALUE,dp[level+1][row][col-row]);
}
}
}
}
return dp[1][0][n];
}
public int leastMinutes(int n) {//打表法AC
if(n<3)return n;
//得到n是严格大于哪个2的幂数
for(int i=1;;++i) {//O(logN)
if((1<<i)<n&&(1<<(i+1))>=n)return i+2;
}
}
}
划分数组
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int[] arr=new int[n];
for(int i=0;i<n;++i) {
arr[i]=scan.nextInt();
}
int max=Integer.MIN_VALUE;
for(int i=0;i<n;++i) {
max=Math.max(max, arr[i]);
}
int a=Math.abs(max-arr[0]);
int b=Math.abs(max-arr[n-1] );
System.out.println(Math.max(a, b));
}
}
最长可整合子数组长度
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int[] arr=new int[n];
for(int i=0;i<n;++i) {
arr[i]=scan.nextInt();
}
int ans=0;
for(int L=0;L<n;++L) {
int min=Integer.MAX_VALUE;
int max=Integer.MIN_VALUE;
for(int R=L;R<n;R++) {
min=Math.min(min, arr[R]);
max=Math.max(max, arr[R]);
if(max-min==R-L) {
ans=Math.max(ans, R-L+1);
}
}
}
System.out.println(ans);
}
}
斐波那契数列问题 O ( l o g N ) O(logN) O(logN) 的解法
import java.util.Scanner;
public class Main {
public static long process(long n) {
long[][] help=new long[][] {{1,1},{1,0}};
long[][] res=MatrixPower(help,n-2);
return (res[0][0]%1000000007+res[1][0]%1000000007)%1000000007;
}
public static long[][] MatrixPower(long[][] help,long x){
long[][] tmp=help;
long[][] ans={{1,0},{0,1}};
for(;x!=0;x>>=1) {
if((x&1)!=0) {
ans=MatrixMultiply(ans,tmp);
}
tmp=MatrixMultiply(tmp,tmp);
}
return ans;
}
public static long[][] MatrixMultiply(long[][] a,long[][] b){
long[][] res=new long[2][2];
for(int i=0;i<2;++i) {
for(int j=0;j<2;++j) {
for(int k=0;k<2;++k) {
res[i][j]+=(a[i][k]%1000000007)*(b[k][j]%1000000007);
}
}
}
return res;
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
long n=scan.nextLong();
if(n<3)System.out.println(1);
else {
long ans=process(n);
System.out.println(ans);
}
}
}
城市路径
public class Solution {
/**
* 将路径数组变为统计数组
* 输入:代表一张图的数组paths
* 将paths数组变为距离数组numArr
*/
public void pathArrToNumArr(int[] paths) {
int origin=0;
int last=0;
int next=0;
for(int i=0;i<paths.length;++i) {
if(i==paths[i]||paths[i]<0)continue;//首都或者已经调整过的城市就跳过
origin=i;
last=i;
next=paths[i];
while(next!=paths[next]&&paths[next]>=0) {
int tmp=paths[next];
paths[next]=last;
last=next;
next=tmp;
}
if(next==paths[next]) {//遇到了首都
next=last;
int p=0;
while(next!=origin) {
last=paths[next];
paths[next]=--p;
next=last;
}
paths[next]=--p;
}else {//
int p=paths[next];
next=last;
while(next!=origin) {
last=paths[next];
paths[next]=--p;
next=last;
}
paths[next]=--p;
}
}
//System.out.println("每个城市到首都的距离: "+Arrays.toString(paths));
int index,distance;
for(int i=0;i<paths.length;++i) {
if(i==paths[i]) {
paths[i]=0;
break;
}
}
for(int i=0;i<paths.length;++i) {
if(paths[i]<0) {//i位置可以开始跳转,否则直接跳过
// origin=i;
index=i;
distance=Math.abs(paths[index]);
paths[index]=0;
while(true){
if(paths[distance]>=0) {
paths[distance]++;
if(paths[index]<0)
paths[index]=0;
break;
}
int tmp=Math.abs(paths[distance]);
index=distance;
paths[distance]=1;
distance=tmp;
}
}
}
paths[0]=1;//后面的都不会跳到0位置
//System.out.println(Arrays.toString(paths));
}
}
分糖果问题
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int[] arr=new int[n];
for(int i=0;i<n;++i) {
arr[i]=scan.nextInt();
}
int[] left=new int[n];
int[] right=new int[n];
left[0]=1;
right[n-1]=1;
for(int i=1;i<n;++i) {
if(arr[i]>arr[i-1]) {
left[i]=left[i-1]+1;
}else {
left[i]=1;
}
}
for(int i=n-2;i>=0;--i) {
if(arr[i]>arr[i+1]) {
right[i]=right[i+1]+1;
}else {
right[i]=1;
}
}
int ans=0;
for(int i=0;i<n;++i) {
ans+=Math.max(left[i], right[i]);
}
System.out.println(ans);
}
}
分糖果问题进阶
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int[] arr=new int[n];
for(int i=0;i<n;++i) {
arr[i]=scan.nextInt();
}
int[] left=new int[n];
int[] right=new int[n];
left[0]=1;
right[n-1]=1;
for(int i=1;i<n;++i) {
if(arr[i]>arr[i-1]) {
left[i]=left[i-1]+1;
}else if(arr[i]==arr[i-1]){
left[i]=left[i-1];
}else {
left[i]=1;
}
}
for(int i=n-2;i>=0;--i) {
if(arr[i]>arr[i+1]) {
right[i]=right[i+1]+1;
}else if(right[i]==right[i+1]){
right[i]=right[i+1];
}else {
right[i]=1;
}
}
int ans=0;
for(int i=0;i<n;++i) {
ans+=Math.max(left[i], right[i]);
}
System.out.println(ans);
}
}