目录
一、两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
来源:力扣(LeetCode)
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map = new HashMap();
for(int i = 0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){
return new int[]{map.get(target-nums[i]),i};
}
map.put(nums[i],i);
}
return new int []{-1,-1};
}
}
二、删除排序链表中的重复元素
存在一个按升序排列的链表,给你这个链表的头节点 head
,请你删除所有重复的元素,使每个元素 只出现一次 。
返回同样按升序排列的结果链表。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
//终止条件
if(head==null||head.next==null){
return head;
}
//缩短列表
head.next = deleteDuplicates(head.next);
//返回条件
if(head.val==head.next.val){
//向后移动
head = head.next;
return head;
}
return head;
}
}
三、两两交换
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
//终止条件
if(head==null||head.next==null){
return head;
}
//任务 交换head 和 head.next
ListNode next = head.next;
head.next = swapPairs(next.next);
next.next = head;
//返回条件
return next;
}
}
四、旋转列表
给你一个链表的头节点 head
,旋转链表,将链表每个节点向右移动 k
个位置。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode rotateRight(ListNode head, int k) {
int length = 1;
ListNode tmp = head;
if(head==null){
return head;
}
while(tmp.next!=null){
length++;
tmp = tmp.next;
}
k = k%length;
if(k==0){
return head;
}
tmp.next = head;
for(int i = 0;i<length-k;i++){
tmp = tmp.next;
}
ListNode newNode = tmp.next;
tmp.next = null;
return newNode;
}
}
五、斐波那契数列
public class Test03 {
static int fbnq(int a){
//终止条件
if(a==1||a==2){
return 1;
}
// 递归 求前俩个数之和
int num = fbnq(a-1)+fbnq(a-2);
// 返回
return num;
}
public static void main(String[] args) {
int i = 10;
// 1 1 2 3 5 8 13 21 34 55
System.out.println("fbnq(i) = " + fbnq(i));
}
}
六、中序遍历二叉树
实现一个二叉搜索树迭代器类BSTIterator ,表示一个按中序遍历二叉搜索树(BST)的迭代器:
BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在于 BST 中的数字,且该数字小于 BST 中的任何元素。
boolean hasNext() 如果向指针右侧遍历存在数字,则返回 true ;否则返回 false 。
int next()将指针向右移动,然后返回指针处的数字。
注意,指针初始化为一个不存在于 BST 中的数字,所以对 next() 的首次调用将返回 BST 中的最小元素。
你可以假设 next() 调用总是有效的,也就是说,当调用 next() 时,BST 的中序遍历中至少存在一个下一个数字。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class BSTIterator {
//存储左子树
Deque<TreeNode> deque = new ArrayDeque<>();
public BSTIterator(TreeNode root) {
//左子树
dfsLeft(root);
}
//递归 存储左子树
public void dfsLeft(TreeNode tree){
while(tree!=null){
deque.addLast(tree);
tree = tree.left;
}
}
public int next() {
//获取左子树
TreeNode tNode = deque.pollLast();
//右子树
dfsLeft(tNode.right);
//输出
return tNode.val;
}
public boolean hasNext() {
return !deque.isEmpty();
}
}
/**
* Your BSTIterator object will be instantiated and called as such:
* BSTIterator obj = new BSTIterator(root);
* int param_1 = obj.next();
* boolean param_2 = obj.hasNext();
*/
七、子集II
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
class Solution {
public static List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> retList = new ArrayList<>();
retList.add(new ArrayList<>());
//如果为空 返回
if (nums == null || nums.length == 0) return retList;
Arrays.sort(nums);
//开始循环
int yb = 1;
for (int i = 0; i < nums.length; i++) {
int size = retList.size();
if (i > 0 && nums[i] != nums[i - 1]) {
yb = size;
}
for (int j = size-yb; j < size; j++) {
List<Integer> list = new ArrayList(retList.get(j));
list.add(nums[i]);
retList.add(list);
}
}
return retList;
}
}
七、丑数1
给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false 。
丑数 就是只包含质因数 2、3 和/或 5 的正整数。
class Solution {
public boolean isUgly(int n) {
int[] a = {2,3,5};
if(n==1){
return true;
}
if(n==0){
return false;
}
for(int i:a){
while(n%i==0){
n = n/i;
}
}
return n==1;
}
}
八、寻找旋转排序数组中的最小值
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,4]
若旋转 7 次,则可以得到 [0,1,4,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。
给你一个可能存在 重复 元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
class Solution {
public int findMin(int[] nums) {
int low = 0;
int high = nums.length - 1;
while (low < high) {
int pivot = low + (high - low) / 2;
if (nums[pivot] < nums[high]) {
high = pivot;
}
else if (nums[pivot] > nums[high]) {
low = pivot + 1;
}
else {
high -= 1;
}
}
return nums[low];
}
}
九、最大数
给定一组非负整数 nums
,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。
class Solution {
public String largestNumber(int[] nums) {
String[] h=new String[nums.length];
for(int i=0;i<nums.length;i++) h[i]=String.valueOf(nums[i]);
Arrays.sort(h,new Comparator<String>(){
@Override
public int compare(String a,String b){
if (a.charAt(0)!= b.charAt(0)) {
return b.charAt(0) - a.charAt(0);
}
String l1=a+b;
String l2=b+a;
return l2.compareTo(l1);
}
});
if(h[0].charAt(0)=='0') return "0";
StringBuilder sb=new StringBuilder();
for(String ky:h) sb.append(ky);
return sb.toString();
}
}
十、丑数2
给你一个整数 n
,请你找出并返回第 n
个 丑数 。
丑数 就是只包含质因数 2
、3
和/或 5
的正整数。
class Solution {
public int nthUglyNumber(int n) {
int[] dp = new int[n + 1];
dp[1] = 1;
int p2 = 1, p3 = 1, p5 = 1;
for (int i = 2; i <= n; i++) {
int num2 = dp[p2] * 2, num3 = dp[p3] * 3, num5 = dp[p5] * 5;
dp[i] = Math.min(Math.min(num2, num3), num5);
if (dp[i] == num2) {
p2++;
}
if (dp[i] == num3) {
p3++;
}
if (dp[i] == num5) {
p5++;
}
}
return dp[n];
}
}
十一、打劫
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。
class Solution {
public int rob(int[] nums) {
int length = nums.length;
if (length == 1) {
return nums[0];
} else if (length == 2) {
return Math.max(nums[0], nums[1]);
}
return Math.max(robRange(nums, 0, length - 2), robRange(nums, 1, length - 1));
}
public int robRange(int[] nums, int start, int end) {
int first = nums[start], second = Math.max(nums[start], nums[start + 1]);
for (int i = start + 2; i <= end; i++) {
int temp = second;
second = Math.max(first + nums[i], second);
first = temp;
}
return second;
}
}
十二、存在重复数组3
class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
TreeSet<Long> set = new TreeSet<Long>();
for(int i = 0;i<nums.length;i++){
Long ceiling = set.ceiling((long) nums[i]-(long)t);
if(ceiling!=null&&ceiling<=(long) nums[i]+(long)t){
return true;
}
set.add((long)nums[i]);
if(i>=k){
set.remove((long)nums[i-k]);
}
}
return false;
}
}
十三、下一个更大元素I
给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。
例1
输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
对于 num1 中的数字 4 ,你无法在第二个数组中找到下一个更大的数字,因此输出 -1 。
对于 num1 中的数字 1 ,第二个数组中数字1右边的下一个较大数字是 3 。
对于 num1 中的数字 2 ,第二个数组中没有下一个更大的数字,因此输出 -1 。
-----------
例2
输入: nums1 = [2,4], nums2 = [1,2,3,4].
输出: [3,-1]
解释:
对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。
对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出 -1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-greater-element-i
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
单调栈法
理解:单调栈法使用map+队列来实现,由于是找后面一个最大值,所以采用倒序循环,队列用于存储循环游标当前的右边的最大值,当发现还有最大值时,pop比它小的元素(最后剩下的就是当前循环元素的右边第一个最大值)。
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Map<Integer,Integer> map = new HashMap<>();
Deque<Integer> deque = new ArrayDeque();
//反向遍历
for(int i = nums2.length-1;i>=0;i--){
int num = nums2[i];
while (!deque.isEmpty()&&deque.peek()<=num){
deque.pop();
}
map.put(num,deque.isEmpty()?-1:deque.peek());
deque.push(num);
}
int res[] = new int[nums1.length];
for (int i = 0;i<nums1.length;i++){
res[i] = map.get(nums1[i]);
}
return res;
}
}
暴力法
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
for (int i = 0; i < nums1.length; i++) {
int nex = 0;
int num = nums1[i];
for (int j = 0; j < nums2.length; j++) {
if (nex == 1||nums1[i] == nums2[j]) {
nex = 1;
}
if (nex == 1) {
if (nums1[i] < nums2[j]) {
nums1[i] = nums2[j];
break;
}
}
}
if(nums1[i]==num){
nums1[i] = -1;
}
}
return nums1;
}
}
十四、全排列(回溯)
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> linkedList = new ArrayList<>();
List<Integer> list = new LinkedList<>();
for (Integer i :
nums) {
list.add(i);
}
suanFa(0,list,linkedList);
return linkedList;
}
public void suanFa(Integer first,List<Integer> list,List<List<Integer>> LinkedList){
if(first==list.size()){
LinkedList.add(new ArrayList<>(list));
}
for (int i = first; i < list.size(); i++) {
Collections.swap(list,first,i);
suanFa(first+1,list,LinkedList);
Collections.swap(list,first,i);
}
}
}
十五、全排列II
有重复数字
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> linkedList = new ArrayList<>();
List<Integer> list = new LinkedList<>();
for (Integer i :
nums) {
list.add(i);
}
HashSet<Integer> set = new HashSet<>();
suanFa(0,list,linkedList,set);
return linkedList;
}
public void suanFa(Integer first,List<Integer> list,List<List<Integer>> LinkedList,HashSet<Integer> set){
if(first==list.size()){
if (set.add(list.hashCode())) {
LinkedList.add(new LinkedList<>(list));
}
}
for (int i = first; i < list.size(); i++) {
if(first!=i&&list.get(first).compareTo(list.get(i))==0){
continue;
}else {
Collections.swap(list,first,i);
suanFa(first+1,list,LinkedList,set);
Collections.swap(list,first,i);
}
}
}
}
十六、路径交叉(归纳法)
给你一个整数数组 distance 。
从 X-Y 平面上的点 (0,0) 开始,先向北移动 distance[0] 米,然后向西移动 distance[1] 米,向南移动 distance[2] 米,向东移动 distance[3] 米,持续移动。也就是说,每次移动后你的方位会发生逆时针变化。
判断你所经过的路径是否相交。如果相交,返回 true ;否则,返回 false 。
一共四种情况
class Solution {
public static boolean isSelfCrossing(int[] distance) {
int size = distance.length;
if (size <= 3) {
return false;
}
for (int i = 3; i < distance.length; i++) {
if (distance[i - 3] >= distance[i - 1] && distance[i - 2] <= distance[i]) {
return true;
}
if (i >= 4 && distance[i - 3] == distance[i - 1] && distance[i - 4] + distance[i] >= distance[i - 2]
) {
return true;
}
if (i >= 4 && distance[i - 3] >= distance[i - 1] && distance[i] >= distance[i - 2]
) {
return true;
}
if (i >= 5 && distance[i - 5] + distance[i - 1] >= distance[i - 3] && distance[i - 4] + distance[i] >= distance[i - 2]
&& distance[i - 3] >= distance[i - 1] && distance[i - 2] >= distance[i - 4]
) {
return true;
}
}
return false;
}
}
十七、分糖果
Alice 有 n 枚糖,其中第 i 枚糖的类型为 candyType[i] 。Alice 注意到她的体重正在增长,所以前去拜访了一位医生。
医生建议 Alice 要少摄入糖分,只吃掉她所有糖的 n / 2 即可(n 是一个偶数)。Alice 非常喜欢这些糖,她想要在遵循医生建议的情况下,尽可能吃到最多不同种类的糖。
给你一个长度为 n 的整数数组 candyType ,返回: Alice 在仅吃掉 n / 2 枚糖的情况下,可以吃到糖的最多种类数
示例 1:
输入:candyType = [1,1,2,2,3,3]
输出:3
解释:Alice 只能吃 6 / 2 = 3 枚糖,由于只有 3 种糖,她可以每种吃一枚。
示例 2:
输入:candyType = [1,1,2,3]
输出:2
解释:Alice 只能吃 4 / 2 = 2 枚糖,不管她选择吃的种类是 [1,2]、[1,3] 还是 [2,3],她只能吃到两种不同类的糖。
class Solution {
public int distributeCandies(int[] candyType) {
Set set = new HashSet();
int size = candyType.length;
for (int i:candyType) {
if(set.size()>=size/2){
break;
}
set.add(i);
}
size = size/2;
if(set.size()==size){
return size;
}else {
return set.size();
}
}
}
十八、键盘行
给你一个字符串数组 words
,只返回可以使用在 美式键盘 同一行的字母打印出来的单词。
美式键盘 中:
- 第一行由字符
"qwertyuiop"
组成。 - 第二行由字符
"asdfghjkl"
组成。 - 第三行由字符
"zxcvbnm"
组成。
输入:words = ["Hello","Alaska","Dad","Peace"] 输出:["Alaska","Dad"]
输入:words = ["omk"] 输出:[]
方法1
public Map<Character,Integer> initData(){
Map<Character,Integer> map = new HashMap<>();
String key1 = "zxcvbnm";
String key2 = "asdfghjkl";
String key3 = "qwertyuiop";
String[] key = {key1,key2,key3};
int i = 1;
for (String c :
key) {
for (Character keys :
c.toCharArray()) {
map.put(keys,i);
map.put(keys.toString().toUpperCase().charAt(0),i);
}
i++;
}
return map;
}
public String[] findWords(String[] words) {
Map<Character,Integer> map = initData();
List<String> list = new ArrayList();
for (String word :
words) {
if(word.equals("")){
continue;
}
int num = map.get(word.charAt(0));
boolean res = true;
for (Character c :
word.toCharArray()) {
if(map.get(c)!=num){
res = false;
break;
}
}
if(res){
list.add(word);
}
}
return list.toArray(new String[list.size()]);
}
方法2
12210...代表abcdefg字母的行号
class Solution {
public String[] findWords(String[] words) {
String key = "12210111011122000010020202";
List<String> list = new ArrayList();
for (String word :
words) {
if(word.equals("")){
continue;
}
boolean res = true;
int i = key.charAt(Character.toLowerCase(word.charAt(0))-'a');
for (Character c :
word.toCharArray()) {
if(i!=(key.charAt(Character.toLowerCase(c)-'a'))){
res = false;
break;
}
}
if(res){
list.add(word);
}
}
return list.toArray(new String[list.size()]);
}
}
十九、只出现一次的数字|||
异或运算
class Solution {
public int[] singleNumber(int[] nums) {
int sum = 0;
for (int i :
nums) {
sum ^= i;
}
int tmp = sum==Integer.MIN_VALUE?sum:sum&(-sum);
int type1 = 0;
int type2 = 0;
for (int i :
nums) {
if((tmp&i)==0){
type1^=i;
}else {
type2^=i;
}
}
return new int[]{type1,type2};
}
}
自己的思路
class Solution {
public int[] singleNumber(int[] nums) {
Set<Integer> set = new HashSet<>();
for (Integer num :
nums) {
if(set.contains(num)){
set.remove(num);
}else {
set.add(num);
}
}
Object [] tmp = set.toArray();
int[] res = new int[set.size()];
int tp = 0;
for (Object i :
tmp) {
res[tp] = (Integer) i;
tp+=1;
}
return res;
}
}
二十、搜索二维矩阵II
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列
输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出:true
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int l = matrix.length-1;
int y = matrix[0].length-1;
int x = 0;
while (y>=0&&x<=l){
if(matrix[x][y]==target){
return true;
}
if(matrix[x][y]>target){
y--;
}else {
x++;
}
}
return false;
}
}
二十一、接雨水I
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
思路:采用动态规划算法,两边往中间遍历,存储左、右边最大值,遍历时,如果左边最大值比右边大则计算右边可接雨水,右边游标向左移一位,反之。
class Solution {
public int trap(int[] height) {
int leftMax = height[0];
int left = 0;
int right = height.length-1;
int rightMax = height[height.length-1];
int sum = 0;
while (left!=right){
if(height[left]>leftMax){
leftMax = height[left];
}
if(height[right]>rightMax){
rightMax = height[right];
}
if(leftMax>=rightMax){
sum+=rightMax-height[right];
right--;
}else {
sum+=leftMax-height[left];
left++;
}
}
return sum;
}
}
二十二、接雨水II
二十三、找最大子序列
给你一个整数数组 arr 和一个整数 difference,请你找出并返回 arr 中最长等差子序列的长度,该子序列中相邻元素之间的差等于 difference 。
子序列 是指在不改变其余元素顺序的情况下,通过删除一些元素或不删除任何元素而从 arr 派生出来的序列。
示例 1:
输入:arr = [1,2,3,4], difference = 1
输出:4
解释:最长的等差子序列是 [1,2,3,4]。
示例 2:
输入:arr = [1,3,5,7], difference = 1
输出:1
解释:最长的等差子序列是任意单个元素。
示例 3:
输入:arr = [1,5,7,8,5,3,4,2,1], difference = -2
输出:4
解释:最长的等差子序列是 [7,5,3,1]。
提示:
1 <= arr.length <= 105
-104 <= arr[i], difference <= 104
class Solution {
public static int longestSubsequence(int[] arr, int difference) {
Map<Integer, Integer> max = new HashMap<>();
int res = 1;
for (int arri:arr) {
int num = max.getOrDefault(arri - difference,0)+1;
max.put(arri, num);
res = res > num ? res : num;
}
return res;
// return Collections.max(max.values());
}
}
二十四、丢失的数字
给定一个包含 [0, n]
中 n
个数的数组 nums
,找出 [0, n]
这个范围内没有出现在数组中的那个数。
示例 1:
输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。
示例 2:
输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。
解法1 公式
多次运行发现for循环比stream快
class Solution {
public int missingNumber(int[] nums) {
// int sum = Arrays.stream(nums).sum();
int sum = 0;
for (int i :
nums) {
sum+=i;
}
int length = nums.length;
length = length*(length+1)/2;
return length-sum;
}
}
解法2 位运算 异或
class Solution {
public int missingNumber(int[] nums) {
int res = 0;
for(int i :nums){
res^=i;
}
for(int i = 0;i<=nums.length;i++){
res^=i;
}
return res;
}
}
二十五、范围求和II
给定一个初始元素全部为 0,大小为 m*n 的矩阵 M 以及在 M 上的一系列更新操作。
操作用二维数组表示,其中的每个操作用一个含有两个正整数 a 和 b 的数组表示,含义是将所有符合 0 <= i < a 以及 0 <= j < b 的元素 M[i][j] 的值都增加 1。
在执行给定的一系列操作后,你需要返回矩阵中含有最大整数的元素个数。
示例 1:
输入:
m = 3, n = 3
operations = [[2,2],[3,3]]
输出: 4
解释:
初始状态, M =
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]
执行完操作 [2,2] 后, M =
[[1, 1, 0],
[1, 1, 0],
[0, 0, 0]]
执行完操作 [3,3] 后, M =
[[2, 2, 1],
[2, 2, 1],
[1, 1, 1]]
M 中最大的整数是 2, 而且 M 中有4个值为2的元素。因此返回 4。
class Solution {
public int maxCount(int m, int n, int[][] ops) {
int minx = 999999;
int miny = 999999;
if(ops.length==0){
return m*n;
}
for (int a[] : ops
) {
minx = minx < a[0] ? minx : a[0];
miny = miny < a[1] ? miny : a[1];
}
return minx*miny;
}
}
二十六、猜数字游戏
你在和朋友一起玩 猜数字(Bulls and Cows)游戏,该游戏规则如下:
写出一个秘密数字,并请朋友猜这个数字是多少。朋友每猜测一次,你就会给他一个包含下述信息的提示:
猜测数字中有多少位属于数字和确切位置都猜对了(称为 "Bulls", 公牛),
有多少位属于数字猜对了但是位置不对(称为 "Cows", 奶牛)。也就是说,这次猜测中有多少位非公牛数字可以通过重新排列转换成公牛数字。
给你一个秘密数字 secret 和朋友猜测的数字 guess ,请你返回对朋友这次猜测的提示。
提示的格式为 "xAyB" ,x 是公牛个数, y 是奶牛个数,A 表示公牛,B 表示奶牛。
请注意秘密数字和朋友猜测的数字都可能含有重复数字。
示例 1:
输入: secret = "1807", guess = "7810"
输出: "1A3B"
解释: 数字和位置都对(公牛)用 '|' 连接,数字猜对位置不对(奶牛)的采用斜体加粗标识。
"1807"
|
"7810"
示例 2:
输入: secret = "1123", guess = "0111"
输出: "1A1B"
解释: 数字和位置都对(公牛)用 '|' 连接,数字猜对位置不对(奶牛)的采用斜体加粗标识。
"1123" "1123"
| or |
"0111" "0111"
注意,两个不匹配的 1 中,只有一个会算作奶牛(数字猜对位置不对)。通过重新排列非公牛数字,其中仅有一个 1 可以成为公牛数字。
class Solution {
public String getHint(String secret, String guess) {
int [] a = {0,0,0,0,0,0,0,0,0,0};
int yb = 0;
char [] b = guess.toCharArray();
int res1 = 0;
int res2 = 0;
for (Character sec :
secret.toCharArray()) {
if(b[yb]==sec) {
res1++;
b[yb] = 'a';
}else {
a[sec-'0'] +=1;
}
yb++;
}
for (Character sec :
b) {
if(sec=='a'){
continue;
}
if(a[sec-'0']>0){
a[sec-'0'] -=1;
res2++;
}
}
return res1+"A"+res2+"B";
}
}
二十七、提莫
在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。
当提莫攻击艾希,艾希的中毒状态正好持续 duration 秒。
正式地讲,提莫在 t 发起发起攻击意味着艾希在时间区间 [t, t + duration - 1](含 t 和 t + duration - 1)处于中毒状态。如果提莫在中毒影响结束 前 再次攻击,中毒状态计时器将会 重置 ,在新的攻击之后,中毒影响将会在 duration 秒后结束。
给你一个 非递减 的整数数组 timeSeries ,其中 timeSeries[i] 表示提莫在 timeSeries[i] 秒时对艾希发起攻击,以及一个表示中毒持续时间的整数 duration 。
返回艾希处于中毒状态的 总 秒数。
示例 1:
输入:timeSeries = [1,4], duration = 2
输出:4
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 4 秒,提莫再次攻击艾希,艾希中毒状态又持续 2 秒,即第 4 秒和第 5 秒。
艾希在第 1、2、4、5 秒处于中毒状态,所以总中毒秒数是 4 。
class Solution {
public int findPoisonedDuration(int[] timeSeries, int duration) {
int size = timeSeries.length;
int zmTime = 0;
int keep = 0;
for (int i = 0; i < size - 1; i++) {
if (timeSeries[i] + duration - 1 < timeSeries[i + 1]) {
zmTime += duration;
} else {
keep = timeSeries[i + 1] - timeSeries[i];
zmTime += keep;
keep = duration - keep;
}
}
return zmTime + duration;
}
}
二十八、网格照明
在大小为 n x n 的网格 grid 上,每个单元格都有一盏灯,最初灯都处于 关闭 状态。
给你一个由灯的位置组成的二维数组 lamps ,其中 lamps[i] = [rowi, coli] 表示 打开 位于 grid[rowi][coli] 的灯。即便同一盏灯可能在 lamps 中多次列出,不会影响这盏灯处于 打开 状态。
当一盏灯处于打开状态,它将会照亮 自身所在单元格 以及同一 行 、同一 列 和两条 对角线 上的 所有其他单元格 。
另给你一个二维数组 queries ,其中 queries[j] = [rowj, colj] 。对于第 j 个查询,如果单元格 [rowj, colj] 是被照亮的,则查询结果为 1 ,否则为 0 。在第 j 次查询之后 [按照查询的顺序] ,关闭 位于单元格 grid[rowj][colj] 上及相邻 8 个方向上(与单元格 grid[rowi][coli] 共享角或边)的任何灯。
返回一个整数数组 ans 作为答案, ans[j] 应等于第 j 次查询 queries[j] 的结果,1 表示照亮,0 表示未照亮。
class Solution {
/**
* 对角线求法:
* 截距 x-y x+y
*/
public int[] gridIllumination(int n, int[][] lamps, int[][] queries) {
Map<Integer, Integer> x = new HashMap<>();
Map<Integer, Integer> y = new HashMap<>();
//x-y
Map<Integer, Integer> diagonalLineX = new HashMap<>();
//x+y
Map<Integer, Integer> diagonalLineY = new HashMap<>();
Set<Long> pointSet = new HashSet<>();
int[] res = new int[queries.length];
//存灯 去重
for (int[] coordinates : lamps) {
if (pointSet.contains(hashAlgorithm(coordinates[0], coordinates[1]))) {
continue;
} else {
pointSet.add(hashAlgorithm(coordinates[0], coordinates[1]));
insert(coordinates[0], x);
insert(coordinates[1], y);
insert(coordinates[0] - coordinates[1], diagonalLineX);
insert(coordinates[0] + coordinates[1], diagonalLineY);
}
}
//去灯
int[][] Path = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, -1}, {1, 1}, {-1, -1}, {-1, 1},{0,0}};
int i = 0;
for (int querie[] : queries) {
//判断querie亮的没有
if (check(querie[0], x)) {
res[i] = 1;
}
if (check(querie[1], y)) {
res[i] = 1;
}
if (check(querie[0] - querie[1], diagonalLineX)) {
res[i] = 1;
}
if (check(querie[0] + querie[1], diagonalLineY)) {
res[i] = 1;
}
i++;
//遍历路径 找到要去掉的灯
for (int j = 0; j < Path.length; j++) {
Integer tmpX = querie[0] + Path[j][0];
Integer tmpY = querie[1] + Path[j][1];
Long value = hashAlgorithm(tmpX, tmpY);
if (pointSet.contains(value)) {
pointSet.remove(value);
//去点 四个map value -1
delete(tmpX,x);
delete(tmpY,y);
delete(tmpX-tmpY,diagonalLineX);
delete(tmpX+tmpY,diagonalLineY);
}
}
}
return res;
}
public Long hashAlgorithm(Integer a, Integer b) {
return (long) a + ((long) b << 32);
}
public void insert(Integer coordinates, Map<Integer, Integer> map) {
map.put(coordinates, map.getOrDefault(coordinates, 0) + 1);
}
public void delete(Integer coordinates, Map<Integer, Integer> map) {
if (map.get(coordinates) != null) {
map.put(coordinates, map.get(coordinates) - 1);
}
if(map.get(coordinates)<=0){
map.put(coordinates,null);
}
}
public boolean check(Integer coordinates, Map<Integer, Integer> map) {
return map.get(coordinates) != null;
}
}