日常刷题,以easy和medium为主练练手
985. Sum of Even Numbers After Queries
每次查询只需要O(1)的时间复杂度
class Solution {
public int[] sumEvenAfterQueries(int[] A, int[][] queries) {
int oddSum=0,evenSum=0;
for(int i=0;i<A.length;i++){
if((A[i] & 1)==1)
oddSum+=A[i];
else
evenSum+=A[i];
}
int[] ans=new int[queries.length];
for(int i=0;i<ans.length;i++){
//A[queries[i][1]]为偶数 queries[i][0]为偶数
if((A[queries[i][1]] & 1)==0){
if((queries[i][0] & 1)==0)
{
evenSum+=queries[i][0];
ans[i]=evenSum;
A[queries[i][1]]+=queries[i][0];
}
else //A[queries[i][1]]为偶数 queries[i][0]为奇数
{
evenSum-=A[queries[i][1]];
ans[i]=evenSum;
oddSum+=queries[i][0]+A[queries[i][1]];
A[queries[i][1]]+=queries[i][0];
}
}
else{
//A[queries[i][1]]为奇数,queries[i][0]为偶数
if((queries[i][0] & 1)==0){
oddSum+=queries[i][0];
A[queries[i][1]]+=queries[i][0];
ans[i]=evenSum;
}
else //A[queries[i][1]]为奇数,queries[i][0]为奇数
{
evenSum+=A[queries[i][1]]+queries[i][0];
oddSum-=A[queries[i][1]];
ans[i]=evenSum;
A[queries[i][1]]+=queries[i][0];
}
}
}
return ans;
}
}
class Solution {
public boolean canMeasureWater(int x, int y, int z) {
if(z==0 || z==x || z==y || x+y==z)
return true;
if(x+y<z)
return false;
int GCD=gcd(x,y);
return GCD==0?false:z%GCD==0;
}
int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
}
399. Evaluate Division
一个图论可达性搜索的问题
class Solution {
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
int n_points = 0;
HashMap<String, Integer> map = new HashMap<>();
for (List<String> list : equations) {
for (String s : list) {
if (!map.containsKey(s)) {
map.put(s, n_points++);
}
}
}
double[][] adj = new double[n_points][n_points];
for (int i = 0; i < equations.size(); i++) {
String start = equations.get(i).get(0);
int startIndex = map.get(start);
String end = equations.get(i).get(1);
int endIndex = map.get(end);
adj[startIndex][endIndex] = values[i];
if (values[i] != 0.0)
adj[endIndex][startIndex] = 1 / values[i];
}
double[] ans = new double[queries.size()];
Arrays.fill(ans, -1.0);
for (int i = 0; i < ans.length; i++) {
String a = queries.get(i).get(0);
String b = queries.get(i).get(1);
if (!map.containsKey(a) || !map.containsKey(b))
ans[i] = -1.0;
else if(a.equals(b)){
ans[i]=1.0;
}
else {
int start = map.get(a), end = map.get(b);
System.out.println(start+end);
Queue<double[]> que = new LinkedList<>();
boolean[] visited = new boolean[n_points + 1];
for (int k = 0; k < n_points; k++) {
if (adj[start][k] != 0.0) {
visited[k] = true;
System.out.print(k);
double[] tmp = {(double) k, adj[start][k]};
que.add(tmp);
}
}
while (!que.isEmpty()) {
double[] tmp = que.poll();
int source = (int) tmp[0];
if (source == end) {
ans[i] = tmp[1];
System.out.println("haha");
break;
}
for (int j = 0; j < n_points; j++) {
if (!visited[j] && adj[source][j] != 0.0) {
double[] temp = {(double) j, adj[source][j] * tmp[1]};
System.out.println("xixi"+adj[source][j] * tmp[1]);
que.add(temp);
visited[j] = true;
}
}
}
}
}
return ans;
}
}
443. String Compression
双指针算法,原地
class Solution {
public int compress(char[] chars) {
int i=0,j=0;
while(j<chars.length){
int idx=j;
char c=chars[idx];
int count=1;
while(idx+1<chars.length && chars[idx+1]==c){
count++;
idx++;
}
if(count==1)
{
chars[i++]=chars[j];
}
else{
chars[i++]=chars[j];
String str=String.valueOf(count);
for(int n=0;n<str.length();n++)
chars[i++]=str.charAt(n);
}
j=idx+1;
}
return i;
}
}
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
return dfs(root, null);
}
private int dfs(TreeNode root, TreeNode parent) {
if (root == null) return 0;
if (root.left == null && root.right == null && parent != null && parent.left == root) {
return root.val;
}
return dfs(root.left, root) + dfs(root.right, root);
}
}
class Solution {
public void reverseString(char[] s) {
int i=0,j=s.length-1;
while(i<j){
char tmp=s[i];
s[i++]=s[j];
s[j--]=tmp;
}
}
}
345. Reverse Vowels of a String
class Solution {
public String reverseVowels(String s) {
char[] sb=s.toCharArray();
int i=0,j=s.length()-1;
while(i<j){
while(i<j && check(sb[i]))
i++;
while(i<j && check(sb[j]))
j--;
if(i>=j)
break;
else{
char tmp=sb[i];
sb[i++]=sb[j];
sb[j--]=tmp;
}
}
return new String(sb);
}
public boolean check(char c){
return c!='a' && c!='e' && c!='i' && c!='o' && c!='u' && c!='A' && c!='E' && c!='I' && c!='O' && c!='U';
}
}
1074. Number of Submatrices That Sum to Target
比较容易想到的是二维前缀和方法,先用平方复杂度求二维前缀和,但是后面的矩形枚举暴力解法,大概是O(m^4),过不了最后两个测试数据,因此需要优化。不能AC,算法如下:
class Solution {
public int numSubmatrixSumTarget(int[][] matrix, int target) {
int m=matrix.length,n=matrix[0].length,ans=0;
int[][] preSum=new int[m+1][n+1];
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++)
{
preSum[i][j]=preSum[i-1][j]+preSum[i][j-1]-preSum[i-1][j-1]+matrix[i-1][j-1];
System.out.print(preSum[i][j]+" ");
}
System.out.println();
}
int count=m*n;
for(int i=1;i<=count;i++){
for(int j=i;j<=count;j++){
int x1=(i-1)/n+1,y1=(i-1)%n+1,x2=(j-1)/n+1,y2=(j-1)%n+1;
if(x2<x1 || y2<y1)
continue;
int tmp=preSum[x2][y2]-preSum[x2][y1-1]-preSum[x1-1][y2]+preSum[x1-1][y1-1];
if(tmp==target)
{
ans++;
}
}
}
return ans;
}
}
再讨论区学习了一下,有一种O(m^3)的算法如下:
先求出每排数据的前缀和,前缀和一维的,算法复杂度为O(N^2)。对于处在不同的列
class Solution {
public int numSubmatrixSumTarget(int[][] m, int t) {
for(int[] r : m) {
int sum = 0;
for(int i = 0; i < r.length; i++) {
sum += r[i];
r[i] = sum;
}
}
int res = 0;
for(int c1 = 0; c1 < m[0].length; c1++) {
for(int c2 = c1; c2 < m[0].length; c2++) {
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
int preSum = 0;
for(int r = 0; r < m.length; r++) {
int cur = m[r][c2] - (c1 > 0 ? m[r][c1-1] : 0);
preSum += cur;
res += map.getOrDefault(preSum - t, 0);
map.put(preSum, map.getOrDefault(preSum, 0) + 1);
}
}
}
return res;
}
}
1051. Height Checker
直接对原数组进行排序,然后检查位置就行
class Solution {
public int heightChecker(int[] heights) {
int[] sorted=heights.clone();
Arrays.sort(sorted);
int ans=0;
for(int i=0;i<heights.length;i++)
{
if(sorted[i]!=heights[i])
ans++;
}
return ans;
}
}
1052. Grumpy Bookstore Owner
定长滑动窗口问题,只要求出固定长度窗口内不满意的客户转为满意的最大值,然后要总客户数量减去原始不满意的人数,最后加上转变的人数。
class Solution {
public int maxSatisfied(int[] customers, int[] grumpy, int X) {
int total=0,unsatisfyTotal=0;
for(int i=0;i<customers.length;i++)
{
total+=customers[i];
unsatisfyTotal+=grumpy[i]*customers[i];
}
int convert=0,maxConvert=0;
for(int i=0;i<customers.length;i++){
convert+=grumpy[i]*customers[i];
if(i>=X)
convert-=grumpy[i-X]*customers[i-X];
maxConvert=Math.max(maxConvert,convert);
}
return total-unsatisfyTotal+maxConvert;
}
}
1053. Previous Permutation With One Swap
这个问题与Next Element III有点像,算法思路一致。
class Solution {
public int[] prevPermOpt1(int[] A) {
int j=A.length-1;
for(;j-1>=0;j--){
if(A[j-1]>A[j])
break;
}
if(j==0)
return A;
int q=j-1,delta=Integer.MAX_VALUE,index=j;
for(;j<A.length;j++){
if(A[q]-A[j]>0 && A[q]-A[j]<delta)
{
delta=A[q]-A[j];
index=j;
}
}
int tmp=A[index];
A[index]=A[q];
A[q]=tmp;
return A;
}
}
class Solution {
public int[] rearrangeBarcodes(int[] barcodes) {
HashMap<Integer,Integer> counter=new HashMap<>();
int maxCount=Integer.MIN_VALUE,val=barcodes[0];
for(int i:barcodes){
int fre=counter.containsKey(i)?counter.get(i):0;
counter.put(i,fre+1);
if(fre+1>maxCount){
maxCount=fre+1;
val=i;
}
}
int[] ans=new int[barcodes.length];
int i=0;
while(maxCount>0){
ans[i]=val;
maxCount--;
i+=2;
}
counter.remove(val);
for(int key:counter.keySet()){
int count=counter.get(key);
while(count>0){
i=i>=barcodes.length?1:i;
ans[i]=key;
count--;
i+=2;
}
}
return ans;
}
}
1022. Sum of Root To Leaf Binary Numbers
基础的树深度优先搜索算法,注意这里的位运算需要加括号,因为位运算的优先级要低于加减法运算
class Solution {
public static int ans;
public int sumRootToLeaf(TreeNode root) {
ans=0;
recursive(root,0);
return ans;
}
public static void recursive(TreeNode node,int val)
{
if(node.left==null && node.right==null)
{
ans+=(val<<1)+node.val;
return;
}
int newVal=(val<<1)+node.val;
if(node.left!=null){
recursive(node.left,newVal);
}
if(node.right!=null){
recursive(node.right,newVal);
}
}
}
class Solution {
public boolean divisorGame(int N) {
return (N & 1)==0;
}
}
1026. Maximum Difference Between Node and Ancestor
class Solution {
public int maxAncestorDiff(TreeNode root) {
return recursive(root,Integer.MAX_VALUE,Integer.MIN_VALUE);
}
public static int recursive(TreeNode node,int minVal,int maxVal){
if(node==null)
return 0;
minVal=Math.min(minVal,node.val);
maxVal=Math.max(maxVal,node.val);
if(node.left==null && node.right==null)
return Math.abs(maxVal-minVal);
return Math.max(recursive(node.left,minVal,maxVal),recursive(node.right,minVal,maxVal));
}
}
1023. Camelcase Matching
驼峰命名匹配这个问题描述有点脏,给的样例不全。比如"Ccoo"和"Ccbobo"也是匹配的。以小写字母开头的字符串也是合法的。
class Solution {
public static List<Boolean> camelMatch(String[] queries, String pattern) {
List<Boolean> ans = new LinkedList<>();
List<String> target = partition(pattern);
for (int i = 0; i < queries.length; i++) {
List<String> source = partition(queries[i]);
if (source.size() != target.size()) {
ans.add(false);
continue;
}
int j = 0;
for (; j < source.size(); j++) {
String ps = target.get(j), ss = source.get(j);
if (!isValid(ps, ss)) {
ans.add(false);
break;
}
}
if (j == source.size())
ans.add(true);
}
return ans;
}
//字符串的一节与模式串的一节是否匹配
public static boolean isValid(String target, String source) { //target:模式字符串
for (int i = 0, j = 0; i < target.length(); i++) {
while (j < source.length() && target.charAt(i) != source.charAt(j))
j++;
if (j == source.length())
return false;
else
j++;
}
return true;
}
//字符串拆分
public static List<String> partition(String s) {
int i = 0;
while(i<s.length() && s.charAt(i)>='a' && s.charAt(i)<='z')
i++;
List<String> ans = new ArrayList<>();
while (i < s.length()) {
int j = i;
while (j + 1 < s.length() && s.charAt(j + 1) >= 'a' && s.charAt(j + 1) <= 'z')
j++;
ans.add(s.substring(i, j + 1));
i = j + 1;
}
for (int n = 0; n < ans.size(); n++)
System.out.println(ans.get(n));
return ans;
}
}
1037. Valid Boomerang
当三点不共线时,即为true。边界条件的判断有些脏。第一行的排序实际上不需要,不过使用lambda表达式替代比较器代码简洁不少。
class Solution {
public boolean isBoomerang(int[][] points) {
Arrays.sort(points,(a,b)->a[0]-b[0]==0?a[1]-b[1]:a[0]-b[0]);
if(points[0][0]==points[1][0] && points[1][0]==points[2][0])
return false;
if((points[0][0]==points[1][0] && points[0][1]==points[1][1]) || (points[1][0]==points[2][0] && points[1][1]==points[2][1]) )
return false;
if(points[1][0]-points[0][0]==0 || points[2][0]-points[0][0]==0)
return true;
double k1=(double)(points[1][1]-points[0][1])/(points[1][0]-points[0][0]);
double k2=(double)(points[2][1]-points[0][1])/(points[2][0]-points[0][0]);
return k1!=k2;
}
}
1034. Coloring A Border
对于连通分量采用BFS进行搜索,再判断是否为边缘元素,代码有点冗长,时间复杂度较高,但是空间复杂度特别好。
class Solution {
class Coordinate{
int x;
int y;
public Coordinate(int x,int y){
this.x=x;
this.y=y;
}
}
public static boolean isValid(int[][] grid,int i,int j){
int m=grid.length,n=grid[0].length;
return i>=0 && i<m && j>=0 && j<n && grid[i][j]==CC && !visited[i][j];
}
public static boolean isBorder(int[][] grid,int i,int j){
int m=grid.length,n=grid[0].length;
if(i==0 || i==m-1 || j==0 || j==n-1)
return true;
return grid[i-1][j]!=grid[i][j] || grid[i+1][j]!=grid[i][j] || grid[i][j-1]!=grid[i][j] || grid[i][j+1]!=grid[i][j];
}
public static int CC;
public static boolean[][] visited;
public int[][] colorBorder(int[][] grid, int r0, int c0, int color)
{
int m=grid.length,n=grid[0].length;
CC=grid[r0][c0];
visited=new boolean[m][n];
Queue<Coordinate> queue=new LinkedList<>();
queue.add(new Coordinate(r0,c0));
visited[r0][c0]=true;
LinkedList<Coordinate> ans=new LinkedList();
while(!queue.isEmpty())
{
Coordinate coor=queue.poll();
int x=coor.x,y=coor.y;
if(isBorder(grid,x,y))
ans.add(coor);
for(int dx=-1;dx<=1;dx++)
{
for(int dy=-1;dy<=1;dy++)
{
if(Math.abs(dx+dy)==1 && isValid(grid,x+dx,y+dy))
{
queue.add(new Coordinate(x+dx,y+dy));
visited[x+dx][y+dy]=true;
System.out.println(x+dx);
System.out.println(y+dy);
}
}
}
}
for(Coordinate c:ans)
grid[c.x][c.y]=color;
return grid;
}
}
1007. Minimum Domino Rotations For Equal Row
暴力枚举1,2,…,6在两排中需要旋转的次数,计算时需要两个计数变量来存储,最后得到最小值。
class Solution {
public int minDominoRotations(int[] A, int[] B) {
int ans=Integer.MAX_VALUE;
for(int i=1;i<=6;i++)
{
int a1=0,a2=0;
for(int j=0;j<A.length;j++){
if(A[j]==i && B[j]!=i)
a2++;
else if(A[j]!=i && B[j]==i)
a1++;
else if(A[j]!=i && B[j]!=i)
{
a1=Integer.MAX_VALUE;
a2=Integer.MAX_VALUE;
break;
}
}
ans=Math.min(ans,Math.min(a1,a2));
}
return ans==Integer.MAX_VALUE?-1:ans;
}
}
1008. Construct Binary Search Tree from Preorder Traversal
中规中矩的二叉搜索树的反序列化,类似于由中序遍历和后序遍历重建二叉树
class Solution {
public TreeNode bstFromPreorder(int[] preorder) {
return recursive(preorder,0,preorder.length-1);
}
public static TreeNode recursive(int[] preorder,int i,int j){
if(i>j)
return null;
TreeNode node=new TreeNode(preorder[i]);
int k=i+1;
for(;k<=j;k++){
if(preorder[k]>preorder[i])
break;
}
node.left=recursive(preorder,i+1,k-1);
node.right=recursive(preorder,k,j);
return node;
}
}