题目及示例
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
代码:
class Solution {
public int search(int[] nums, int target) {
int begin=0;
int end=nums.length-1;
int mid;
while(begin<=end){
mid=(begin+end)/2;
if(target>nums[mid]){
begin=mid+1;
}else if(target<nums[mid]){
end=mid-1;
}else{
return mid;
}
}
return -1;
}
}
题解:
题目及示例
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例 1:
输入:n = 5, bad = 4
输出:4
解释:
调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。
示例 2:
输入:n = 1, bad = 1
输出:1
提示:1 <= bad <= n <= 231 - 1
错误代码(时间复杂度太高,超时)
/* The isBadVersion API is defined in the parent class VersionControl.
boolean isBadVersion(int version); */
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int first=1;
int last=n;
int result=1;
if(n==1){
result=1;
}else{
while(first+1<=last){
int mid=(first+last)/2;
if(isBadVersion(mid)&&isBadVersion(mid+1)){
last=mid;
}else if((!isBadVersion(mid))&&(!isBadVersion(mid+1))){
first=mid;
}else if((!isBadVersion(mid))&&isBadVersion(mid+1)){
result=mid+1;
break;
}
}
}
return result;
}
}
正确代码
/* The isBadVersion API is defined in the parent class VersionControl.
boolean isBadVersion(int version); */
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int first=1;
int last=n;
while(first<last){//循环直至左右端点相同
int mid=first+(last-first)/2;//防止计算时溢出
if(isBadVersion(mid)){
last=mid;//[first,mid]
}else {
first=mid+1;//[mid+1,last]
}
}
return first;//first==last
}
}
题解:
1 <= bad <= n <= 231 - 1
),mid不能直接等于(first+last)/2,要等于first+(last-first)/2,以防止计算时溢出。题目及示例
猜数字游戏的规则如下:
每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):
-1:我选出的数字比你猜的数字小 pick < num
1:我选出的数字比你猜的数字大 pick > num
0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num
返回我选出的数字。
示例 1:
输入:n = 10, pick = 6
输出:6
示例 2:
输入:n = 1, pick = 1
输出:1
提示:1 <= n <= 2^31 - 1 1 <= pick <= n
代码:
public class Solution extends GuessGame {
public int guessNumber(int n) {
int first=1;
int last=n;
while(first<last){
int mid=first+(last-first)/2;
if(guess(mid)<=0){
last=mid;//[first,mid]
}else{
first=mid+1;//[mid+1,last]
}
}
return first;//first=end
}
}
题目及示例
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log2 n) 的算法。
示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2
输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7
输出: 4
示例 4:
输入: nums = [1,3,5,6], target = 0
输出: 0
代码
class Solution {
public int searchInsert(int[] nums, int target) {
int begin=0;
int end=nums.length-1;
int mid;
while(begin<=end){
mid=(begin+end)/2;
if(target>nums[mid]){
begin=mid+1;
}else if(target<nums[mid]){
end=mid-1;
}else{
return mid;
}
}
return begin;
}
}
题解
704二分查找
差不多,不同的是没查到目标数字的话就输出应该插入的下标,正好是begin。题目及示例
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
代码:
class Solution {
public int[] sortedSquares(int[] nums) {
int []a=new int[nums.length];
for(int i=0;i<nums.length;i++){
a[i]=nums[i]*nums[i];
}
Arrays.sort(a);
return a;
}
}
题解
题目及示例
给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]
提示:
1 <= nums.length <= 105
-2^31 <= nums[i] <= 2^31 - 1
0 <= k <= 105
代码
class Solution {
public void rotate(int[] nums, int k) {
int []a=new int[nums.length];
int n=nums.length;
for(int i=0;i<n;i++){
a[(i+k)%n]=nums[i];
}
//for(int i=0;i
// nums[i]=a[i];
//}
// System.out.print("[");
// for(int j=0;j
// System.out.print(nums[j]);
// if(j!=n-1){
// System.out.print(",");
// }
// }
// System.out.print("]");
System.arraycopy(a,0,nums,0,n);//浅度复制,把a数组赋值给nums数组
}
}
题解:
题目及示例
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
代码:
class Solution {
public void moveZeroes(int[] nums) {
for(int i=0;i<nums.length;i++){
for(int j=i;j<nums.length;j++){
if(nums[i]==0&&nums[j]!=0){
nums[i]=nums[j];
nums[j]=0;
break;
}
}
}
}
}
题解:
题目及示例
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入:s = [“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:
输入:s = [“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]
提示:
1 <= s.length <= 105
s[i] 都是 ASCII 码表中的可打印字符
代码:
class Solution {
public void reverseString(char[] s) {
for(int i=0;i<s.length/2;i++){
char t;
t=s[i];
s[i]=s[s.length-i-1];
s[s.length-i-1]=t;
}
}
}
题解:
题目及示例
给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。
示例:
输入:“Let’s take LeetCode contest”
输出:“s’teL ekat edoCteeL tsetnoc”
提示:
在字符串中,每个单词由单个空格分隔,并且字符串中不会有任何额外的空格。
代码1:
class Solution {
public String reverseWords(String s) {
String []str=s.split(" ");
String afterReverse="";
for(int i=0;i<str.length;i++){
StringBuffer sb = new StringBuffer(str[i]);
if(i!=str.length-1){
afterReverse+=sb.reverse().toString()+" ";
}else{
afterReverse+=sb.reverse().toString();
}
}
return afterReverse;
}
}
代码2:
class Solution {
public String reverseWords(String s) {
String []str=s.split(" ");
StringBuffer sb = new StringBuffer();
StringBuffer sb1 = new StringBuffer();
for(int i=0;i<str.length;i++){
sb = new StringBuffer(str[i]);
if(i!=str.length-1){
sb1.append(sb.reverse());
sb1.append(" ");
}else{
sb1.append(sb.reverse());
}
}
return sb1.toString();
}
}
题解:
题目及示例
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
提示:给定链表的结点数介于 1 和 100 之间。
代码:
/**
- 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 middleNode(ListNode head) {
ListNode slow=head,fast=head;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
}
return slow;
}
}
题解:
题目及示例
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[1]
提示:
链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
代码:
/**
- 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 removeNthFromEnd(ListNode head, int n) {
ListNode dummy=new ListNode(0,head);
ListNode first=head;
ListNode second=dummy;
for(int i=0;i<n;i++){
first=first.next;
}
while(first!=null){
first=first.next;
second=second.next;
}
second.next=second.next.next;
ListNode ans=dummy.next;//头结点
return ans;
}
}
题解:
题目及示例
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
示例 4:
输入: s = “”
输出: 0
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
代码:
class Solution {
public int lengthOfLongestSubstring(String s) {
int n=s.length();
Set<Character> set=new HashSet<>();
int right=-1;
int max=0;
for(int left=0;left<n;left++){
if(left!=0){
set.remove(s.charAt(left-1));
}
while(right+1<n&&!set.contains(s.charAt(right+1)))
{
set.add(s.charAt(right+1));
right++;
}
max=Math.max(max,right-left+1);
}
return max;
}
}
题解:
和剑指 Offer II 014. 字符串中的变位词一样
题目及示例
给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的 子串 。
示例 1:
输入:s1 = “ab” s2 = “eidbaooo”
输出:true
解释:s2 包含 s1 的排列之一 (“ba”).
示例 2:
输入:s1= “ab” s2 = “eidboaoo”
输出:false
提示:
1 <= s1.length, s2.length <= 104
s1 和 s2 仅包含小写字母
代码:
class Solution {
public boolean checkInclusion(String s1, String s2) {
int n=s1.length();
int m=s2.length();
if(n>m){
return false;
}
int []cnt1=new int[26];
int []cnt2=new int[26];
for(int i=0;i<n;i++){
++cnt1[s1.charAt(i)-'a'];
++cnt2[s2.charAt(i)-'a'];
}
if(Arrays.equals(cnt1,cnt2)){
return true;
}
for(int i=n;i<m;i++){
++cnt2[s2.charAt(i)-'a'];
--cnt2[s2.charAt(i-n)-'a'];
if(Arrays.equals(cnt1,cnt2)){
return true;
}
}
return false;
}
}
题解:
题目及示例
有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间。
给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。
为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。
最后返回经过上色渲染后的图像。
示例 1:
输入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析:
在图像的正中间,(坐标(sr,sc)=(1,1)),
在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,
因为它不是在上下左右四个方向上与初始点相连的像素点。
注意:
image 和 image[0] 的长度在范围 [1, 50] 内。
给出的初始点将满足 0 <= sr < image.length 和 0 <= sc < image[0].length。
image[i][j] 和 newColor 表示的颜色值在范围 [0, 65535]内。
代码:
class Solution {
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
int currColor=image[sr][sc];
if(currColor!=newColor){
dfs(image,sr,sc,currColor,newColor);
}
return image;
}
public void dfs(int [][]image,int x,int y,int currColor,int newColor){
int []dx={1,0,0,-1};
int []dy={0,1,-1,0};//上,右,左,下
if(image[x][y]==currColor){
image[x][y]=newColor;
for(int i=0;i<4;i++){
int mx=x+dx[i];
int my=y+dy[i];
if(mx>=0&&mx<image.length
&&my>=0&&my<image[0].length){
dfs(image,mx,my,currColor,newColor);
}
}
}
}
}
题解:
题目及示例
给你一个大小为 m x n 的二进制矩阵 grid 。
岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
岛屿的面积是岛上值为 1 的单元格的数目。
计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
示例 1:
输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:6
解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。
示例 2:
输入:grid = [[0,0,0,0,0,0,0,0]]
输出:0
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j] 为 0 或 1
代码:
class Solution {
public int maxAreaOfIsland(int[][] grid) {
int ans=0;
int n=grid.length;
int m=grid[0].length;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
ans=Math.max(ans,dfs(grid,i,j));
}
}
return ans;
}
public int dfs(int [][]grid,int x,int y){
if(x<0||x==grid.length||y<0||
y==grid[0].length||grid[x][y]==0){
return 0;
}
grid[x][y]=0;
int []di={1,0,0,-1};
int []dj={0,1,-1,0};//上,右,左,下
int ans=1;
for(int k=0;k<4;k++){
int mi=x+di[k];
int mj=y+dj[k];
ans+=dfs(grid,mi,mj);
}
return ans;
}
}
题解:
题目及示例
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始。
代码:
/**
* 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 Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1==null){
return root2;
}
if(root2==null){
return root1;
}
TreeNode t=new TreeNode(root1.val+root2.val);
t.left=mergeTrees(root1.left,root2.left);
t.right=mergeTrees(root1.right,root2.right);
return t;
}
}
题解:
题目及示例
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
进阶:
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
示例:
输入:root = [1,2,3,4,5,6,7]
输出:[1,#,2,3,#,4,5,6,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,’#’ 标志着每一层的结束。
提示:
树中节点的数量少于 4096
-1000 <= node.val <= 1000
代码:
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
if (root == null) {
return null;
}
connect(root.left, root.right);
return root;
}
public void connect(Node left, Node right) {
if (left != null && right != null) {
left.next = right;
connect(left.left, left.right);
connect(left.right, right.left);
connect(right.left, right.right);
}
}
}
给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。
示例 1:
输入:mat = [[0,0,0],[0,1,0],[0,0,0]]
输出:[[0,0,0],[0,1,0],[0,0,0]]
示例 2:
输入:mat = [[0,0,0],[0,1,0],[1,1,1]]
输出:[[0,0,0],[0,1,0],[1,2,1]]
提示:
m == mat.length
n == mat[i].length
1 <= m, n <= 104
1 <= m * n <= 104
mat[i][j] is either 0 or 1.
mat 中至少有一个 0
代码:
class Solution {
static int [][]dir={{-1,0},{1,0},{0,-1},{0,1}};
public int[][] updateMatrix(int[][] mat) {
int n=mat.length;
int m=mat[0].length;
int [][]dist=new int[n][m];
Queue<int[]> q=new LinkedList<int[]>();
boolean [][] b=new boolean[n][m];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(mat[i][j]==0){
q.offer(new int[]{i,j});//进队列
b[i][j]=true;
}
}
}
//广度优先搜索
while(!q.isEmpty()){
int []cell=q.poll();//出队列
int i=cell[0],j=cell[1];
for(int d=0;d<4;d++){
int ni=i+dir[d][0];
int nj=j+dir[d][1];
if(ni>=0&&ni<n&&nj>=0&&nj<m&&!b[ni][nj]){
dist[ni][nj]=dist[i][j]+1;
q.offer(new int[]{ni,nj});
b[ni][nj]=true;
}
}
}
return dist;
}
}
题解:
题目及示例
在给定的网格中,每个单元格可以有以下三个值之一:
值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会腐烂。
返回直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1。
示例 1:
输入:[[2,1,1],[1,1,0],[0,1,1]]
输出:4
示例 2:
输入:[[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。
示例 3:
输入:[[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。
提示:
1 <= grid.length <= 10
1 <= grid[0].length <= 10
grid[i][j] 仅为 0、1 或 2
代码:
class Solution {
//配合得到下上左右的元素的二维数组
static int [][]dir={{-1,0},{1,0},{0,-1},{0,1}};
public int orangesRotting(int[][] grid) {
int n=grid.length;
int m=grid[0].length;
int total=0;
Queue<Integer> q=new LinkedList<Integer>();
Map<Integer,Integer> depth=new HashMap<Integer,Integer>();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(grid[i][j]==2){
//转化成索引唯一的一维数组
int code=i*m+j;
q.offer(code);//存储腐烂橘子
//存储句子变为腐烂的时间,key为句子的以为数组下标,
//value为变腐烂的时间,刚开始时间为0。
depth.put(code,0);
}
}
}
//广度优先搜索
while(!q.isEmpty()){
int code=q.poll();//出队列
int i=code/m,j=code%m;
for(int d=0;d<4;d++){
int ni=i+dir[d][0];
int nj=j+dir[d][1];
if(ni>=0&&ni<n&&nj>=0&&nj<m&&grid[ni][nj]==1){
grid[ni][nj]=2;
int ncode=ni*m+nj;
q.offer(ncode);
//计数的关键,元素grid[i][j]的上下左右元素的腐烂时间应该一致
depth.put(ncode,depth.get(code)+1);
total=depth.get(ncode);
}
}
}
//如果有元素为1,说明还有新鲜橘子,返回-1
for(int []row:grid){
for(int v:row){
if(v==1){
return -1;
}
}
}
return total;
}
}
题解:
题目及示例
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
示例 2:
输入:n = 1, k = 1
输出:[[1]]
提示:
1 <= n <= 20
1 <= k <= n
代码:
class Solution {
List<List<Integer>> list =new ArrayList<List<Integer>>();
List<Integer> li=new ArrayList<Integer>();
public List<List<Integer>> combine(int n, int k) {
dfs(1,n,k);
return list;
}
public void dfs(int cur,int n,int k){
//临时数组li的长度和【cur,n】的长度相加如果小于k,则数组为空。
if(li.size()+n-cur+1<k){
return;
}
//临时数组li长度为k,则加入到答案数组list
if(li.size()==k){
list.add(new ArrayList<Integer>(li));
return;
}
//如果选择当前位置,把cur加入到li数组
li.add(cur);
dfs(cur+1,n,k);
//如果不选择当前位置
li.remove(li.size()-1);
dfs(cur+1,n,k);
}
}
题解:
题目及示例
给定一个不含重复数字的数组 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]]
提示:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同
代码:
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> ans=new ArrayList<List<Integer>>();
List<Integer> output=new ArrayList<Integer>();
for(int num:nums){
output.add(num);
}
int n=nums.length;
backtrack(n,output,ans,0);
return ans;
}
public void backtrack(int n,List<Integer> output,
List<List<Integer>> ans,int first){
if(first==n){
ans.add(new ArrayList<Integer>(output));
}
for(int i=first;i<n;i++){
//动态维护数组
Collections.swap(output,first,i);
//继续递归填下一个数
backtrack(n,output,ans,first+1);
//撤销操作
Collections.swap(output,first,i);
}
}
}
题解:
和动态规划的题一样
题目及示例
给定一个三角形 triangle ,找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。
示例 1:
输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:
2
3 4
6 5 7
4 1 8 3
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
示例 2:
输入:triangle = [[-10]]
输出:-10
提示:
1 <= triangle.length <= 200
triangle[0].length == 1
triangle[i].length == triangle[i - 1].length + 1
-104 <= triangle[i][j] <= 104
代码:
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n=triangle.size();
int [][]a=new int[n][n];
a[0][0]=triangle.get(0).get(0);
for(int i=1;i<n;i++){
a[i][0]=a[i-1][0]+triangle.get(i).get(0);
for(int j=1;j<i;j++){
a[i][j]=Math.min(a[i-1][j-1],a[i-1][j])+triangle.get(i).get(j);
}
a[i][i]=a[i-1][i-1]+triangle.get(i).get(i);
}
int min=a[n-1][0];
for(int k=1;k<n;k++){
min=Math.min(min,a[n-1][k]);
}
return min;
}
}
题解:
题目及示例
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109
代码:
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftIndex=binarySearch(nums,target,true);
int rightIndex=binarySearch(nums,target,false)-1;
System.out.println(leftIndex+" "+rightIndex);
if(leftIndex<=rightIndex&&rightIndex<nums.length&&nums[leftIndex]==target&&nums[rightIndex]==target){
return new int[]{leftIndex,rightIndex};
}
return new int[]{-1,-1};
}
public int binarySearch(int []nums,int target,boolean flag){
int left=0;
int right=nums.length-1;
int ans=nums.length;
while(left<=right){
int mid=(left+right)/2;
if(nums[mid]>target||(nums[mid]>=target&&flag)){
right=mid-1;
ans=mid;
}else{
left=mid+1;
}
}
return ans;
}
}
题解:
题目及示例
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,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 ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
示例 1:
输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
示例 2:
输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。
示例 3:
输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。
提示:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums 中的所有整数 互不相同
nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转
代码:
class Solution {
public int findMin(int[] nums) {
//第一种方法
// Arrays.sort(nums);
// return nums[0];
//第二种方法
int ans=nums[0];
for(int i=0;i<nums.length-1;i++){
if(nums[i]>nums[i+1]){
ans=nums[i+1];
break;
}
}
return ans;
}
}
题解:
题目及示例
给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 ‘*’、除号 ‘/’ 以及求余符号 ‘%’ 。
注意:
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231−1]。本题中,如果除法结果溢出,则返回 231 − 1
示例 1:
输入:a = 15, b = 2
输出:7
解释:15/2 = truncate(7.5) = 7
示例 2:
输入:a = 7, b = -3
输出:-2
解释:7/-3 = truncate(-2.33333…) = -2
示例 3:
输入:a = 0, b = 1
输出:0
提示:
-231 <= a, b <= 231 - 1
b != 0
代码
class Solution {
public int divide(int a, int b) {
int count=0;
boolean flag=false;
if(b==0){
return 0;
}
if(a==Integer.MIN_VALUE){
if(b==1){
return Integer.MIN_VALUE;
}
if(b==-1){
return Integer.MAX_VALUE;
}
}
if(b==Integer.MIN_VALUE){
if(a==Integer.MIN_VALUE){
return 1;
}else{
return 0;
}
}
if((a>0&&b<0)||(a<0&&b>0)){
flag=true;
}
//防止数字溢出
if(a>0){
a=-a;
}
if(b>0){
b=-b;
}
while(a<=b){
a-=b;
count++;
}
if(flag){
count=-count;
}
return count;
}
}
题解
题目及示例
给定两个 01 字符串 a 和 b ,请计算它们的和,并以二进制字符串的形式输出。
输入为 非空 字符串且只包含数字 1 和 0。
示例 1:
输入: a = “11”, b = “10”
输出: “101”
示例 2:
输入: a = “1010”, b = “1011”
输出: “10101”
提示:
每个字符串仅由字符 ‘0’ 或 ‘1’ 组成。
1 <= a.length, b.length <= 10^4
字符串如果不是 “0” ,就都不含前导零。
代码:
class Solution {
public String addBinary(String a, String b) {
return Integer.toBinaryString(
Integer.parseInt(a,2)+Integer.parseInt(b,2)
);
}
}
题解:
题目及示例
给定一个非负整数 n ,请计算 0 到 n 之间的每个数字的二进制表示中 1 的个数,并输出一个数组。
示例 1:
输入: n = 2
输出: [0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10
示例 2:
输入: n = 5
输出: [0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101
说明 :
0 <= n <= 10^5
代码:
class Solution {
public int[] countBits(int n) {
int []a=new int[n+1];
for(int i=0;i<=n;i++){
int j=i;
while(j!=0){
if(j%2==1){
a[i]++;
}
j=j/2;
}
}
return a;
}
}
题解
题目及示例
给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
示例 1:
输入:nums = [2,2,3,2]
输出:3
示例 2:
输入:nums = [0,1,0,1,0,1,100]
输出:100
提示:
1 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次
代码(哈希表法):
class Solution {
public int singleNumber(int[] nums) {
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int num:nums){
map.put(num,map.getOrDefault(num,0)+1);
}
int ans=0;
for(Map.Entry<Integer,Integer> entry:map.entrySet()){
int num=entry.getKey();
int occ=entry.getValue();
if(occ==1){
ans=num;
break;
}
}
return ans;
}
}
题解:
⌊n/3⌋+1
个元素,即需要的空间为 O(n)。题目及示例
给定一个字符串数组 words,请计算当两个字符串 words[i] 和 words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0。
示例 1:
输入: words = [“abcw”,“baz”,“foo”,“bar”,“fxyz”,“abcdef”]
输出: 16
解释: 这两个单词为 “abcw”, “fxyz”。它们不包含相同字符,且长度的乘积最大。
示例 2:
输入: words = [“a”,“ab”,“abc”,“d”,“cd”,“bcd”,“abcd”]
输出: 4
解释: 这两个单词为 “ab”, “cd”
示例 3:
输入: words = [“a”,“aa”,“aaa”,“aaaa”]
输出: 0
解释: 不存在这样的两个单词。
提示:
2 <= words.length <= 1000
1 <= words[i].length <= 1000
words[i] 仅包含小写字母
代码:
class Solution {
public int maxProduct(String[] words) {
int n=words.length;
int []arr=new int[n];
for(int i=0;i<n;i++){
int a=0;
for(int j=0;j<words[i].length();j++){
a|=(1<<(words[i].charAt(j)-'a'));
}
arr[i]=a;
}
int max=0;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
if((arr[i]&arr[j])==0){
max=Math.max(max,words[i].length()*words[j].length());
}
}
}
return max;
}
}
题解:
题目及示例
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 0 开始计数 ,所以答案数组应当满足 0 <= answer[0] < answer[1] < numbers.length 。
假设数组中存在且只存在一对符合条件的数字,同时一个数字不能使用两次。
示例 1:
输入:numbers = [1,2,4,6,10], target = 8
输出:[1,3]
解释:2 与 6 之和等于目标数 8 。因此 index1 = 1, index2 = 3
示例 2:
输入:numbers = [2,3,4], target = 6
输出:[0,2]
示例 3:
输入:numbers = [-1,0], target = -1
输出:[0,1]
代码:
class Solution {
public int[] twoSum(int[] numbers, int target) {
int []a=new int[2];
int left=0;
int right=numbers.length-1;
if(numbers==null||numbers.length<=0){
return a;
}
while(left<right){
if(numbers[left]+numbers[right]>target){
right--;
}else if(numbers[left]+numbers[right]<target){
left++;
}else if(numbers[left]+numbers[right]==target){
a[0]=left;
a[1]=right;
break;
}
}
return a;
}
}
题解
题目及示例
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a ,b ,c ,使得 a + b + c = 0 ?请找出所有和为 0 且 不重复 的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000
-10^5 <= nums[i] <= 10^5
代码:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
int n=nums.length;
if(nums==null||n<3){
return new ArrayList<>();
}
List<List<Integer>> list=new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<n-2;i++){
if(i>0&&nums[i]==nums[i-1]) continue;
int target=-nums[i];
int left=i+1;
int right=n-1;
while(left<right){
if(nums[left]+nums[right]==target){
list.add(Arrays.asList(nums[i],nums[left],nums[right]));
//去重
while(left<right&&nums[left]==nums[++left]);//如果两个数相等,则进入循环,不能进行下面的步骤;不相等的时候则继续下面的步骤
while(left<right&&nums[right]==nums[--right]);
}else if(nums[left]+nums[right]>target){
right--;
}else{
left++;
}
}
}
return list;
}
}
题解:
题目及示例
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
代码1:(前缀和)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int count=Integer.MAX_VALUE;
int n=nums.length;
if(n==0){
return 0;
}
int []sum=new int[n+1];
for(int i=1;i<n+1;i++){
sum[i]=sum[i-1]+nums[i-1];
}
for(int i=1;i<n+1;i++){
int s=target+sum[i-1];
int bound=Arrays.binarySearch(sum,s);
if(bound<0){
bound=-bound-1;
}
if(bound<=n){
count=Math.min(count,bound-(i-1));
}
}
return count==Integer.MAX_VALUE?0:count;
}
}
题解1:
代码2(弹窗法):
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left=0;
int min=Integer.MAX_VALUE;
int total=0;
for(int right=0;right<nums.length;right++){
total+=nums[right];
while(left<=right&&total>=target){
total-=nums[left];
min=Math.min(min,right-left+1);
left++;
}
}
return min==Integer.MAX_VALUE?0:min;
}
}
题解2:
给定一个正整数数组 nums和整数 k ,请找出该数组内乘积小于 k 的连续的子数组的个数。
示例 1:
输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8 个乘积小于 100 的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。
示例 2:
输入: nums = [1,2,3], k = 0
输出: 0
提示:
1 <= nums.length <= 3 * 104
1 <= nums[i] <= 1000
0 <= k <= 106
代码:
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
int left=0;
int ret=0;
int total=1;
for(int right=0;right<nums.length;right++){
total*=nums[right];
while(left<=right&&total>=k){
total/=nums[left];
left++;
}
if(left<=right){
ret+=(right-left)+1;
}
}
return ret;
}
}
题解:
题目及示例
给定一个整数数组和一个整数 k ,请找到该数组中和为 k 的连续子数组的个数。
示例 1 :
输入:nums = [1,1,1], k = 2
输出: 2
解释: 此题 [1,1] 与 [1,1] 为两种不同的情况
示例 2 :
输入:nums = [1,2,3], k = 3
输出: 2
提示:
1 <= nums.length <= 2 * 104
-1000 <= nums[i] <= 1000
-107 <= k <= 107
代码:
class Solution {
public int subarraySum(int[] nums, int k) {
Map<Integer,Integer> map=new HashMap<>();
map.put(0,1);
int sum=0;//前缀和
int count=0;//记录子数组的个数
for(int i=0;i<nums.length;i++){
sum+=nums[i];
count+=map.getOrDefault(sum-k,0);
map.put(sum,map.getOrDefault(sum,0)+1);
}
return count;
}
}
题解:
题目及示例
给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
示例 1:
输入: nums = [0,1]
输出: 2
说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。
示例 2:
输入: nums = [0,1,0]
输出: 2
说明: [0, 1] (或 [1, 0]) 是具有相同数量 0 和 1 的最长连续子数组。
提示:
1 <= nums.length <= 105
nums[i] 不是 0 就是 1
代码:
class Solution {
public int findMaxLength(int[] nums) {
Map<Integer,Integer> map=new HashMap<>();
int counter=0;//前缀和
int max=0;
map.put(0,-1);
for(int i=0;i<nums.length;i++){
if(nums[i]==1){
counter++;
}else{
counter--;
}
if(map.containsKey(counter)){
int prevIndex=map.get(counter);
max=Math.max(max,i-prevIndex);
}else{
map.put(counter,i);
}
}
return max;
}
}
题解:
前缀和+哈希表法
题目及示例
给你一个整数数组 nums ,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
示例 1:
输入:nums = [1,7,3,6,5,6]
输出:3
解释:
中心下标是 3 。
左侧数之和 sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 ,
右侧数之和 sum = nums[4] + nums[5] = 5 + 6 = 11 ,二者相等。
示例 2:
输入:nums = [1, 2, 3]
输出:-1
解释:
数组中不存在满足此条件的中心下标。
示例 3:
输入:nums = [2, 1, -1]
输出:0
解释:
中心下标是 0 。
左侧数之和 sum = 0 ,(下标 0 左侧不存在元素),
右侧数之和 sum = nums[1] + nums[2] = 1 + -1 = 0 。
提示:
1 <= nums.length <= 104
-1000 <= nums[i] <= 1000
代码:
class Solution {
public int pivotIndex(int[] nums) {
int n=nums.length;
int total=0;
int sum=0;
for(int i=0;i<n;i++){
total+=nums[i];
}
for(int i=0;i<n;i++){
if(2*sum+nums[i]==total){
return i;
}
sum+=nums[i];
}
return -1;
}
}
题解:
题目及示例
给定一个二维矩阵 matrix,以下类型的多个请求:
计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2) 。
实现 NumMatrix 类:
NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
int sumRegion(int row1, int col1, int row2, int col2) 返回左上角 (row1, col1) 、右下角 (row2, col2) 的子矩阵的元素总和。
示例 1:
输入:
[“NumMatrix”,“sumRegion”,“sumRegion”,“sumRegion”]
[[[[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]],[2,1,4,3],[1,1,2,2],[1,2,2,4]]
输出:
[null, 8, 11, 12]
解释:
NumMatrix numMatrix = new NumMatrix([[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]]);
numMatrix.sumRegion(2, 1, 4, 3); // return 8 (红色矩形框的元素总和)
numMatrix.sumRegion(1, 1, 2, 2); // return 11 (绿色矩形框的元素总和)
numMatrix.sumRegion(1, 2, 2, 4); // return 12 (蓝色矩形框的元素总和)
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 200
-105 <= matrix[i][j] <= 105
0 <= row1 <= row2 < m
0 <= col1 <= col2 < n
最多调用 104 次 sumRegion 方法
代码:
class NumMatrix {
int [][]sum;//前缀和
public NumMatrix(int[][] matrix) {
int n=matrix.length;
if(n>0){
int m=matrix[0].length;
sum=new int[n][m+1];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
sum[i][j+1]=sum[i][j]+matrix[i][j];
}
}
}
}
public int sumRegion(int row1, int col1, int row2, int col2) {
int total=0;
for(int i=row1;i<=row2;i++){
total+=sum[i][col2+1]-sum[i][col1];
}
return total;
}
}
题解:
题目及示例
给定两个字符串 s 和 p,找到 s 中所有 p 的 变位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
变位词 指字母相同,但排列不同的字符串。
示例 1:
输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]
解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的变位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的变位词。
示例 2:
输入: s = “abab”, p = “ab”
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 “ab”, 它是 “ab” 的变位词。
起始索引等于 1 的子串是 “ba”, 它是 “ab” 的变位词。
起始索引等于 2 的子串是 “ab”, 它是 “ab” 的变位词。
提示:
1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母
代码:
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> list=new ArrayList<>();
int []a=new int[26];
int []b=new int[26];
int n=p.length();
int m=s.length();
if(n>m){
return list;
}
for(int i=0;i<n;i++){
a[p.charAt(i)-'a']++;
b[s.charAt(i)-'a']++;
}
if(Arrays.equals(a,b)){
list.add(0);
}
for(int i=n;i<m;i++){
b[s.charAt(i)-'a']++;
b[s.charAt(i-n)-'a']--;
if(Arrays.equals(a,b)){
list.add(i-n+1);
}
}
return list;
}
}
题解:
和 3. 无重复字符的最长子串 一样
题目及示例
给定一个字符串 s ,验证 s 是否是 回文串 ,只考虑字母和数字字符,可以忽略字母的大小写。
本题中,将空字符串定义为有效的 回文串 。
示例 1:
输入: s = “A man, a plan, a canal: Panama”
输出: true
解释:“amanaplanacanalpanama” 是回文串
示例 2:
输入: s = “race a car”
输出: false
解释:“raceacar” 不是回文串
提示:
1 <= s.length <= 2 * 105
字符串 s 由 ASCII 字符组成
代码:
class Solution {
public boolean isPalindrome(String s) {
boolean flag=true;
List<Character> list=new ArrayList<>();
String str=s.toLowerCase();
for(int i=0;i<s.length();i++){
if((str.charAt(i)>='0'&&str.charAt(i)<='9')||(str.charAt(i)>='a'&&str.charAt(i)<='z')) {
list.add(str.charAt(i));
}
}
for(int i = 0;i < list.size()/2; i ++){
if(list.get(i)!=list.get(list.size()-i-1)){
flag=false;
break;
}
}
return flag;
}
}
题解:
题目及示例
给定一个非空字符串 s,请判断如果 最多 从字符串中删除一个字符能否得到一个回文字符串。
示例 1:
输入: s = “aba”
输出: true
示例 2:
输入: s = “abca”
输出: true
解释: 可以删除 “c” 字符 或者 “b” 字符
示例 3:
输入: s = “abc”
输出: false
提示:
1 <= s.length <= 105
s 由小写英文字母组成
代码:
class Solution {
public boolean validPalindrome(String s) {
for(int left=0,right=s.length()-1;left<right;left++,right--){
if(s.charAt(left)!=s.charAt(right)){
return hui(s,left+1,right)|| hui(s,left,right-1);
}
}
return true;
}
//判断字符串s的[left,right]是否回文
public boolean hui(String s,int left,int right){
while(left<right){
if(s.charAt(left++)!=s.charAt(right--)){
return false;
}
}
return true;
}
}
题解:
题目及实例
给定一个字符串 s ,请计算这个字符串中有多少个回文子字符串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:s = “abc”
输出:3
解释:三个回文子串: “a”, “b”, “c”
示例 2:
输入:s = “aaa”
输出:6
解释:6个回文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”
提示:
1 <= s.length <= 1000
s 由小写英文字母组成
代码:
class Solution {
public int countSubstrings(String s) {
int n=s.length();
int total=0;
for(int i=0;i<n;i++){
int ans=0;
int num=i+1;
while(num<=n){
// System.out.println(s.substring(i,num));
// System.out.println(hui(s.substring(i,num)));
if(hui(s.substring(i,num))){
++ans;
}
num++;
}
total+=ans;
}
return total;
}
//判断字符串s是否回文
public boolean hui(String s){
StringBuffer sb = new StringBuffer(s);
sb.reverse();//将str倒置的方法
String s1=new String(sb);
if(s.equals(s1)){
return true;
}
return false;
}
}
题解:
equals()
,用==不行题目及示例
给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
提示:
链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引
代码:
/**
- Definition for singly-linked list.
- class ListNode {
- int val;
- ListNode next;
- ListNode(int x) {
- val = x;
- next = null;
- }
- }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> set=new HashSet<>();
while(head!=null){
if(!set.add(head)){
return head;
}
head=head.next;
}
return head;
}
}
题解:
题目及示例
给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at ‘2’
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。
提示:
listA 中节点数目为 m
listB 中节点数目为 n
0 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
如果 listA 和 listB 没有交点,intersectVal 为 0
如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]
代码:
/**
- Definition for singly-linked list.
- public class ListNode {
- int val;
- ListNode next;
- ListNode(int x) {
- val = x;
- next = null;
- }
- }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> set=new HashSet<>();
ListNode ans=new ListNode();
while(headA!=null){
set.add(headA);
headA=headA.next;
}
while(headB!=null){
if(!set.add(headB)){
ans=headB;
break;
}
headB=headB.next;
}
return ans.val==0?null:ans;
}
}
题解:
题目及示例
给定两个 非空链表 l1和 l2 来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例1:
输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]
示例2:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[8,0,7]
示例3:
输入:l1 = [0], l2 = [0]
输出:[0]
提示:
链表的长度范围为 [1, 100]
0 <= node.val <= 9
输入数据保证链表代表的数字无前导 0
进阶:如果输入链表不能修改该如何处理?换句话说,不能对列表中的节点进行翻转。
代码:
/**
- 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 addTwoNumbers(ListNode l1, ListNode l2) {
l1=reverse(l1);
l2=reverse(l2);
int d=0;//进位
ListNode node=new ListNode(0),next=null;
while(l1!=null||l2!=null||d!=0){
int a=l1==null?0:l1.val;
int b=l2==null?0:l2.val;
int sum=a+b+d;
d=sum/10;
node =new ListNode(sum%10,next);
next=node;//逆转链表
l1=l1==null?l1:l1.next;
l2=l2==null?l2:l2.next;
}
return node;
}
public ListNode reverse(ListNode head){
ListNode prev=null;
ListNode curr=head;
while(curr!=null){
ListNode next=curr.next;
curr.next=prev;
prev=curr;
curr=next;
}
return prev;
}
}
题解:
题目及示例
给定一个链表的 头节点 head ,请判断其是否为回文链表。
如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
示例 1:
输入: head = [1,2,3,3,2,1]
输出: true
示例 2:
输入: head = [1,2]
输出: false
提示:
链表 L 的长度范围为 [1, 105]
0 <= node.val <= 9
代码:
/**
* 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 boolean isPalindrome(ListNode head) {
ListNode head1=head;
ListNode index=mid(head);
ListNode head2=reverse(index.next);
boolean flag=true;
while(flag&&head2!=null){
if(head1.val!=head2.val){
flag=false;
}
head1=head1.next;
head2=head2.next;
}
return flag;
}
//找到链表的中心位置
public ListNode mid(ListNode head){
ListNode slow=head;
ListNode fast=head;
while(fast.next!=null&&fast.next.next!= null){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
public ListNode reverse(ListNode head){
ListNode prev=null;
ListNode curr=head;
while(curr!=null){
ListNode next=curr.next;
curr.next=prev;
prev=curr;
curr=next;
}
return prev;
}
}
题解:
题目及示例
多级双向链表中,除了指向下一个节点和前一个节点指针之外,它还有一个子链表指针,可能指向单独的双向链表。这些子列表也可能会有一个或多个自己的子项,依此类推,生成多级数据结构,如下面的示例所示。
给定位于列表第一级的头节点,请扁平化列表,即将这样的多级双向链表展平成普通的双向链表,使所有结点出现在单级双链表中。
示例 1:
输入:head = [1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]
输出:[1,2,3,7,8,11,12,9,10,4,5,6]
示例 2:
输入:head = [1,2,null,3]
输出:[1,3,2]
解释:
输入的多级列表如下图所示:
1—2---NULL
|
3—NULL
示例 3:
输入:head = []
输出:[]
如何表示测试用例中的多级链表?
以 示例 1 为例:
1—2---3—4---5—6–NULL
|
7—8---9—10–NULL
|
11–12–NULL
序列化其中的每一级之后:
[1,2,3,4,5,6,null]
[7,8,9,10,null]
[11,12,null]
为了将每一级都序列化到一起,我们需要每一级中添加值为 null 的元素,以表示没有节点连接到上一级的上级节点。
[1,2,3,4,5,6,null]
[null,null,7,8,9,10,null]
[null,11,12,null]
合并所有序列化结果,并去除末尾的 null 。
[1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]
提示:
节点数目不超过 1000
1 <= Node.val <= 105
代码:
/*
// Definition for a Node.
class Node {
public int val;
public Node prev;
public Node next;
public Node child;
};
*/
class Solution {
public Node flatten(Node head) {
dfs(head);
return head;
}
public Node dfs(Node node){
Node cur=node;
//记录链表的最后一个节点
Node last=null;
while(cur!=null){
//next表示下一个节点
Node next=cur.next;
//如果有子节点,先处理子节点
if(cur.child!=null){
//子节点最后一个节点
Node childLast=dfs(cur.child);
next=cur.next;
//将node与child相连
cur.next=cur.child;
cur.child.prev=cur;
//如果next不为空,就将last与next相连
if(next!=null){
childLast.next=next;
next.prev=childLast;
}
//将child置为空
cur.child=null;
//最后一个节点变成子节点的最后一个节点
last=childLast;
}else{
//如果没有子节点,则最后一个节点是当前节点
last=cur;
}
cur=next;
}
return last;
}
}
题解:
题目及示例
设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构:
insert(val):当元素 val 不存在时返回 true ,并向集合中插入该项,否则返回 false 。
remove(val):当元素 val 存在时返回 true ,并从集合中移除该项,否则返回 false 。
getRandom:随机返回现有集合中的一项。每个元素应该有 相同的概率 被返回。
示例 :
输入: inputs = [“RandomizedSet”, “insert”, “remove”, “insert”, “getRandom”, “remove”, “insert”, “getRandom”]
[[], [1], [2], [2], [], [1], [2], []]
输出: [null, true, false, true, 2, true, false, 2]
解释:
RandomizedSet randomSet = new RandomizedSet(); // 初始化一个空的集合
randomSet.insert(1); // 向集合中插入 1 , 返回 true 表示 1 被成功地插入
randomSet.remove(2); // 返回 false,表示集合中不存在 2
randomSet.insert(2); // 向集合中插入 2 返回 true ,集合现在包含 [1,2]
randomSet.getRandom(); // getRandom 应随机返回 1 或 2
randomSet.remove(1); // 从集合中移除 1 返回 true 。集合现在包含 [2]
randomSet.insert(2); // 2 已在集合中,所以返回 false
randomSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom 总是返回 2
提示:
-231 <= val <= 231 - 1
最多进行 2 * 105 次 insert , remove 和 getRandom 方法调用
当调用 getRandom 方法时,集合中至少有一个元素
代码:
class RandomizedSet {
Set<Integer> set=new HashSet<Integer>();
/** Initialize your data structure here. */
public RandomizedSet() {
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
public boolean insert(int val) {
if(set.add(val)){
return true;
}
return false;
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
public boolean remove(int val) {
if(set.remove(val)){
return true;
}
return false;
}
/** Get a random element from the set. */
public int getRandom() {
List <Integer> list = new ArrayList<Integer>(set);
int n=list.size();
return list.get(new Random().nextInt(n));
}
}
/**
- Your RandomizedSet object will be instantiated and called as such:
- RandomizedSet obj = new RandomizedSet();
- boolean param_1 = obj.insert(val);
- boolean param_2 = obj.remove(val);
- int param_3 = obj.getRandom();
*/
题解:
用set数组,如果有重复数值,则会加入失败;若无指定数值,移除失败。
题目及示例
给定一个整数数组,判断是否存在重复元素。
如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。
示例 1:
输入: [1,2,3,1]
输出: true
示例 2:
输入: [1,2,3,4]
输出: false
示例 3:
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true
代码
class Solution {
public boolean containsDuplicate(int[] nums) {
boolean flag=false;
Arrays.sort(nums);
for(int i=0;i<nums.length-1;i++){
if(nums[i]==nums[i+1]){
flag=true;
break;
}
}
return flag;
}
}
题解
题目及示例
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
提示:
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
代码:
class Solution {
public int maxSubArray(int[] nums) {
int []a=new int[nums.length+1];
a[0]=nums[0];
for(int i=1;i<nums.length;i++){
if(a[i-1]+nums[i]>nums[i]){
a[i]=a[i-1]+nums[i];
}else{
a[i]=nums[i];
}
}
int max=a[0];
for(int i=1;i<nums.length;i++){
if(a[i]>max){
max=a[i];
}
}
return max;
}
}
题解:
题目及示例
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
2 <= nums.length <= 1^4
-10^9 <= nums[i] <= 10^9
-10^9 <= target <= 10^9
只会存在一个有效答案
代码:
class Solution {
public int[] twoSum(int[] nums, int target) {
int a[]=new int[2];
for(int i=0;i<nums.length-1;i++) {
for(int j=i+1;j<nums.length;j++) {
if(nums[i]+nums[j]==target) {
a[0]=i;
a[1]=j;
break;
}
}
}
return a;
}
}
题解:
题目及示例
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。
示例 3:
输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。
代码
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
for(int i=m;i<nums1.length;i++){
nums1[i]=nums2[i-m];
}
Arrays.sort(nums1);
}
}
题解:
题目及示例
给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
提示:
1 <= nums1.length, nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 1000
代码:
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int index1=0,index2=0;
ArrayList<Integer> list = new ArrayList<Integer>();
while(index1!=nums1.length&&index2!=nums2.length){
if(nums1[index1]==nums2[index2]){
list.add(nums1[index1]);
index1++;
index2++;
}else if(nums1[index1]>nums2[index2]){
index2++;
}else if(nums1[index1]<nums2[index2]){
index1++;
}
}
int[] a = new int[list.size()];
for(int i = 0;i<list.size();i++){
a[i] = list.get(i);
}
return a;
}
}
题解:
题目及示例
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
1 <= prices.length <= 105
0 <= prices[i] <= 104
代码:
class Solution {
public int maxProfit(int[] prices) {
int []dp=new int[prices.length];
dp[0]=prices[0];
int max=0;
for(int i=1;i<prices.length;i++){
dp[i]=(dp[i-1]<prices[i])? dp[i-1]:prices[i];
max=(prices[i]-dp[i])>max? prices[i]-dp[i]:max;
}
return max;
}
}
题解:
题目及示例
给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
示例 2:
输入: numRows = 1
输出: [[1]]
提示: 1 <= numRows <= 30
代码:
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> list=new ArrayList<List<Integer>>();
for(int i=0;i<numRows;i++){
List<Integer> li=new ArrayList<Integer>();
for(int j=0;j<i+1;j++){
if(j==0||j==i){
li.add(1);
}else{
li.add(list.get(i-1).get(j-1)+list.get(i-1).get(j));
}
}
list.add(li);
}
return list;
}
}
题解:
题目及示例
在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原始数据。
给你一个由二维数组 mat 表示的 m x n 矩阵,以及两个正整数 r 和 c ,分别表示想要的重构的矩阵的行数和列数。
重构后的矩阵需要将原始矩阵的所有元素以相同的 行遍历顺序 填充。
如果具有给定参数的 reshape 操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。
示例 1:
输入:mat = [[1,2],[3,4]], r = 1, c = 4
输出:[[1,2,3,4]]
示例 2:
输入:mat = [[1,2],[3,4]], r = 2, c = 4
输出:[[1,2],[3,4]]
提示:
m == mat.length
n == mat[i].length
1 <= m, n <= 100
-1000 <= mat[i][j] <= 1000
1 <= r, c <= 300
代码:
class Solution {
public int[][] matrixReshape(int[][] mat, int r, int c) {
int m=mat.length;
int n=mat[0].length;
int []a=new int[(m*n)];
int [][]b=new int[r][c];
if(r*c!=m*n){
return mat;
}
int ans=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
a[ans]=mat[i][j];
ans++;
}
}
int k=0;
for(int i=0;i<r;i++){
for(int j=0;j<c;j++){
b[i][j]=a[k];
k++;
}
}
return b;
}
}
题解:
题目及示例
给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
示例 1:
输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]
示例 2:
输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]
提示:
m == matrix.length
n == matrix[0].length
1 <= m, n <= 200
-231 <= matrix[i][j] <= 231 - 1
代码:
class Solution {
public void setZeroes(int[][] matrix) {
int n=matrix.length;
int m=matrix[0].length;
boolean []row=new boolean[n];
boolean []col=new boolean[m];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(matrix[i][j]==0){
row[i]=col[j]=true;
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(row[i]||col[j]){
matrix[i][j]=0;
}
}
}
}
}
题解:
题目及示例
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
注意:
一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
空白格用 ‘.’ 表示。
示例 1:
输入:board =
[[“5”,“3”,".",".",“7”,".",".",".","."]
,[“6”,".",".",“1”,“9”,“5”,".",".","."]
,[".",“9”,“8”,".",".",".",".",“6”,"."]
,[“8”,".",".",".",“6”,".",".",".",“3”]
,[“4”,".",".",“8”,".",“3”,".",".",“1”]
,[“7”,".",".",".",“2”,".",".",".",“6”]
,[".",“6”,".",".",".",".",“2”,“8”,"."]
,[".",".",".",“4”,“1”,“9”,".",".",“5”]
,[".",".",".",".",“8”,".",".",“7”,“9”]]
输出:true
示例 2:
输入:board =
[[“8”,“3”,".",".",“7”,".",".",".","."]
,[“6”,".",".",“1”,“9”,“5”,".",".","."]
,[".",“9”,“8”,".",".",".",".",“6”,"."]
,[“8”,".",".",".",“6”,".",".",".",“3”]
,[“4”,".",".",“8”,".",“3”,".",".",“1”]
,[“7”,".",".",".",“2”,".",".",".",“6”]
,[".",“6”,".",".",".",".",“2”,“8”,"."]
,[".",".",".",“4”,“1”,“9”,".",".",“5”]
,[".",".",".",".",“8”,".",".",“7”,“9”]]
输出:false
解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
提示:
board.length == 9
board[i].length == 9
board[i][j] 是一位数字(1-9)或者 ‘.’
代码:
class Solution {
public boolean isValidSudoku(char[][] board) {
int [][]rows=new int[9][9];
int [][]cols=new int[9][9];
int [][][]sub=new int[3][3][9];
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
char tmp=board[i][j];
if(tmp!='.'){
int index=tmp-'0'-1;
rows[i][index]++;
cols[j][index]++;
sub[i/3][j/3][index]++;
if(rows[i][index]>1||
cols[j][index]>1||
sub[i/3][j/3][index]>1){
return false;
}
}
}
}
return true;
}
}
题解:
题目及示例
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
示例:
s = “leetcode”
返回 0
s = “loveleetcode”
返回 2
代码:
class Solution {
public int firstUniqChar(String s) {
Map<Character,Integer> map=new LinkedHashMap<>();
for(int i=0;i<s.length();i++){
map.put(s.charAt(i)
,map.getOrDefault(s.charAt(i),0)+1);
}
char ans='0';
//遍历map,通过value值等于1找到key值
for(Map.Entry<Character,Integer> entry:map.entrySet()){
char ch=entry.getKey();
int num=entry.getValue();
if(num==1){
ans=ch;
break;
}
}
for(int i=0;i<s.length();i++){
if(ans==s.charAt(i)){
return i;
}
}
return -1;
}
}
题解:
题目及示例
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
示例 1:
输入:ransomNote = “a”, magazine = “b”
输出:false
示例 2:
输入:ransomNote = “aa”, magazine = “ab”
输出:false
示例 3:
输入:ransomNote = “aa”, magazine = “aab”
输出:true
提示:
1 <= ransomNote.length, magazine.length <= 105
ransomNote 和 magazine 由小写英文字母组成
代码:
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int n=ransomNote.length();
int m=magazine.length();
int []a=new int[26];
if(n>m){
return false;
}
for(int i=0;i<m;i++){
a[magazine.charAt(i)-'a']++;
}
for(int i=0;i<n;i++){
a[ransomNote.charAt(i)-'a']--;
}
for(int i = 0; i < 26; i++)
{
if(a[i]<0){
return false;
}
}
return true;
}
}
题解:
和383. 赎金信类似
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
示例 1:
输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:
输入: s = “rat”, t = “car”
输出: false
提示:
1 <= s.length, t.length <= 5 * 104
s 和 t 仅包含小写字母
代码:
class Solution {
public boolean isAnagram(String s, String t) {
int n=s.length();
int m=t.length();
int []a=new int[26];
if(n!=m){
return false;
}
for(int i=0;i<n;i++){
a[s.charAt(i)-'a']++;
}
for(int i=0;i<m;i++){
a[t.charAt(i)-'a']--;
}
for(int i = 0; i < 26; i++)
{
if(a[i]!=0){
return false;
}
}
return true;
}
}
题目及示例
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
提示:
链表中节点的数目范围是 [0, 104]
-105 <= Node.val <= 105
pos 为 -1 或者链表中的一个 有效索引 。
代码:
/**
- Definition for singly-linked list.
- class ListNode {
- int val;
- ListNode next;
- ListNode(int x) {
- val = x;
- next = null;
- }
- }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> set=new HashSet<>();
while(head!=null){
if(!set.add(head)){
return true;
}
head=head.next;
}
return false;
}
}
题解:
题目及示例
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列
代码:
/**
- 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 mergeTwoLists(ListNode list1, ListNode list2) {
if(list1==null){
return list2;
}else if(list2==null){
return list1;
}else if(list1.val<list2.val){
list1.next=mergeTwoLists(list1.next,list2);
return list1;
}else{
list2.next=mergeTwoLists(list1,list2.next);
return list2;
}
}
}
题解:
题目及示例
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1
输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7
输出:[]
提示:
列表中的节点数目在范围 [0, 104] 内
1 <= Node.val <= 50
0 <= val <= 50
代码:
/**
* 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 removeElements(ListNode head, int val) {
if(head==null){
return head;
}
head.next=removeElements(head.next, val);
return head.val==val?head.next:head;
}
}
题解:
题目及示例
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
提示:
链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000
代码:
/**
- 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 reverseList(ListNode head) {
ListNode prev=null;
ListNode curr=head;
while(curr!=null){
ListNode next=curr.next;
curr.next=prev;
prev=curr;
curr=next;
}
return prev;
}
}
题解:
题目及示例
存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 。
返回同样按升序排列的结果链表。
示例 1:
输入:head = [1,1,2]
输出:[1,2]
示例 2:
输入:head = [1,1,2,3,3]
输出:[1,2,3]
提示:
链表中节点数目在范围 [0, 300] 内
-100 <= Node.val <= 100
题目数据保证链表已经按升序排列
代码:
/**
* 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){
return head;
}
ListNode cur=head;
//cur.next==null 说明是链表的最后一个元素
while(cur.next!=null){
if(cur.val==cur.next.val){
cur.next=cur.next.next;
}else{
cur=cur.next;
}
}
return head;
}
}
题解:
题目及示例
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 1:
输入:s = “()”
输出:true
示例 2:
输入:s = “()[]{}”
输出:true
示例 3:
输入:s = “(]”
输出:false
示例 4:
输入:s = “([)]”
输出:false
示例 5:
输入:s = “{[]}”
输出:true
提示:
1 <= s.length <= 104
s 仅由括号 ‘()[]{}’ 组成
代码:
class Solution {
public boolean isValid(String s) {
if(s.isEmpty()){
return true;
}
Stack<Character> stack=new Stack<Character>();
for(char c:s.toCharArray()){
if(c=='('){
stack.push(')');
}else if(c=='['){
stack.push(']');
}else if(c=='{'){
stack.push('}');
}else if(stack.empty()||c!=stack.pop()){
return false;
}
}
if(stack.empty()){
return true;
}
return false;
}
}
题解:
题目及示例
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
进阶:
你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。
示例:
输入:
[“MyQueue”, “push”, “push”, “peek”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false
提示:
1 <= x <= 9
最多调用 100 次 push、pop、peek 和 empty
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)
代码:
class MyQueue {
private int front;
private Stack<Integer> s1 = new Stack<>();
private Stack<Integer> s2 = new Stack<>();
public MyQueue() {
}
public void push(int x) {
if(s1.empty()){
front=x;
}
while(!s1.isEmpty()){
s2.push(s1.pop());
}
s2.push(x);
while(!s2.isEmpty()){
s1.push(s2.pop());
}
}
public int pop() {
int p=s1.peek();
s1.pop();
if(!s1.empty()){
front=s1.peek();
}
return p;
}
public int peek() {
return front;
}
public boolean empty() {
return s1.isEmpty();
}
}
/**
- Your MyQueue object will be instantiated and called as such:
- MyQueue obj = new MyQueue();
- obj.push(x);
- int param_2 = obj.pop();
- int param_3 = obj.peek();
- boolean param_4 = obj.empty();
*/
题解:
题目及示例
给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
示例 4:
输入:root = [1,2]
输出:[1,2]
示例 5:
输入:root = [1,null,2]
输出:[1,2]
提示:
树中节点数目在范围 [0, 100] 内
-100 <= Node.val <= 100
代码:
/**
* 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 Solution {
//前序遍历是根结点->左结点-->右结点
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList<Integer>();
preorder(root,list);
return list;
}
public void preorder(TreeNode root,List<Integer> list){
if(root==null){
return;
}
list.add(root.val);
preorder(root.left,list);
preorder(root.right,list);
}
}
题目及示例
给定一个二叉树的根节点 root ,返回它的 中序 遍历。
示例 1:
输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
示例 4:
输入:root = [1,2]
输出:[2,1]
示例 5:
输入:root = [1,null,2]
输出:[1,2]
提示:
树中节点数目在范围 [0, 100] 内
-100 <= Node.val <= 100
代码:
/**
* 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 Solution {
//中序遍历是左结点->根结点-->右结点
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList<Integer>();
inorder(root,list);
return list;
}
public void inorder(TreeNode root,List<Integer> list){
if(root==null){
return;
}
inorder(root.left,list);
list.add(root.val);
inorder(root.right,list);
}
}
题目及示例
给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。
示例 1:
输入:root = [1,null,2,3]
输出:[3,2,1]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
提示:
树中节点的数目在范围 [0, 100] 内
-100 <= Node.val <= 100
代码:
/**
- 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 Solution {
//后序遍历是左结点-->右结点-->根结点
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList<Integer>();
postorder(root,list);
return list;
}
public void postorder(TreeNode root,List<Integer> list){
if(root==null){
return;
}
postorder(root.left,list);
postorder(root.right,list);
list.add(root.val);
}
}
题解三合一
题目及示例
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:
输入:root = [1]
输出:[[1]]
示例 3:
输入:root = []
输出:[]
提示:
树中节点数目在范围 [0, 2000] 内
-1000 <= Node.val <= 1000
代码:
/**
- 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 Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> list=new ArrayList<List<Integer>>();
if(root==null){
return list;
}
Queue<TreeNode> q=new LinkedList<TreeNode>();
q.offer(root);//进队列
while(!q.isEmpty()){
List<Integer> li=new ArrayList<Integer>();
int n=q.size();//获取队列长度
for(int i=0;i<n;i++){
TreeNode node=q.poll();//出队列
li.add(node.val);
if(node.left!=null){
q.offer(node.left);//进队列
}
if(node.right!=null){
q.offer(node.right);//进队列
}
}
list.add(li);
}
return list;
}
}
题解:
题目及示例
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最大深度 3 。
代码:
class Solution {
public int maxDepth(TreeNode root) {
if(root==null){
return 0;
}else{
int l=maxDepth(root.left);
int r=maxDepth(root.right);
return Math.max(l,r)+1;
}
}
}
题解:
题目及示例
给你一个二叉树的根节点 root , 检查它是否轴对称。
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
提示:
树中节点数目在范围 [1, 1000] 内
-100 <= Node.val <= 100
代码:
/**
- 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 Solution {
public boolean isSymmetric(TreeNode root) {
return check(root,root);
}
public boolean check(TreeNode p,TreeNode q){
//如果只有root为空,则一定对称
if(p==null&&q==null){
return true;
}
//如果有一边是null,一边有值,那么一定不对称
if(p==null||q==null){
return false;
}
return p.val==q.val&&check(p.right,q.left)&&check(p.left,q.right);
}
}
题解:
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
代码:
class Solution {
public int singleNumber(int[] nums) {
int ans=0;
for(int i=0;i<nums.length;i++){
ans^=nums[i];
}
return ans;
}
}
题解:
题目及示例
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
示例 2:
输入:[2,2,1,1,1,2,2]
输出:2
进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
代码:
class Solution {
public int majorityElement(int[] nums) {
int n=nums.length;
int num=0;
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int i=0;i<n;i++){
map.put(nums[i],map.getOrDefault(nums[i],0)+1);
}
for(Map.Entry<Integer,Integer> entry:map.entrySet()){
int key=entry.getKey();
int value=entry.getValue();
if(value>n/2){
num=key;
break;
}
}
return num;
}
}
题解:
题目及示例
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1]
输出:[0,1,2]
提示:
n == nums.length
1 <= n <= 300
nums[i] 为 0、1 或 2
进阶:
你可以不使用代码库中的排序函数来解决这道题吗?
你能想出一个仅使用常数空间的一趟扫描算法吗?
代码:
class Solution {
public void sortColors(int[] nums) {
int n=nums.length;
//冒泡排序
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
if(nums[j]<nums[i]){
int t=nums[j];
nums[j]=nums[i];
nums[i]=t;
}
}
}
}
}
题解:
题目及示例
不使用任何内建的哈希表库设计一个哈希映射(HashMap)。
实现 MyHashMap 类:
MyHashMap() 用空映射初始化对象
void put(int key, int value) 向 HashMap 插入一个键值对 (key, value) 。如果 key 已经存在于映射中,则更新其对应的值 value 。
int get(int key) 返回特定的 key 所映射的 value ;如果映射中不包含 key 的映射,返回 -1 。
void remove(key) 如果映射中存在 key 的映射,则移除 key 和它所对应的 value 。
示例:
输入:
[“MyHashMap”, “put”, “put”, “get”, “get”, “put”, “get”, “remove”, “get”]
[[], [1, 1], [2, 2], [1], [3], [2, 1], [2], [2], [2]]
输出:
[null, null, null, 1, -1, null, 1, null, -1]
解释:
MyHashMap myHashMap = new MyHashMap();
myHashMap.put(1, 1); // myHashMap 现在为 [[1,1]]
myHashMap.put(2, 2); // myHashMap 现在为 [[1,1], [2,2]]
myHashMap.get(1); // 返回 1 ,myHashMap 现在为 [[1,1], [2,2]]
myHashMap.get(3); // 返回 -1(未找到),myHashMap 现在为 [[1,1], [2,2]]
myHashMap.put(2, 1); // myHashMap 现在为 [[1,1], [2,1]](更新已有的值)
myHashMap.get(2); // 返回 1 ,myHashMap 现在为 [[1,1], [2,1]]
myHashMap.remove(2); // 删除键为 2 的数据,myHashMap 现在为 [[1,1]]
myHashMap.get(2); // 返回 -1(未找到),myHashMap 现在为 [[1,1]]
提示:
0 <= key, value <= 106
最多调用 104次 put、get 和 remove 方法
代码:
class MyHashMap {
private class Pair{
private int key;
private int value;
public Pair(int key,int value){
this.key=key;
this.value=value;
}
public int getKey(){
return key;
}
public void setKey(int key){
this.key=key;
}
public int getValue(){
return value;
}
public void setValue(int value){
this.value=value;
}
}
private static final int BASE=769;
private LinkedList []data;
public MyHashMap() {
data=new LinkedList[BASE];
for(int i=0;i<BASE;i++){
data[i]=new LinkedList<>();
}
}
public void put(int key, int value) {
int h=hash(key);
Iterator<Pair> iterator =data[h].iterator();
while(iterator.hasNext()){
Pair pair =iterator.next();
if(pair.getKey()==key){
pair.setValue(value);
return;
}
}
data[h].offerLast(new Pair(key,value));
}
public int get(int key) {
int h=hash(key);
Iterator<Pair> iterator =data[h].iterator();
while(iterator.hasNext()){
Pair pair =iterator.next();
if(pair.getKey()==key){
return pair.value;
}
}
return -1;
}
public void remove(int key) {
int h=hash(key);
Iterator<Pair> iterator =data[h].iterator();
while(iterator.hasNext()){
Pair pair =iterator.next();
if(pair.getKey()==key){
data[h].remove(pair);
return;
}
}
}
private static int hash(int key){
return key%BASE;
}
}
/**
- Your MyHashMap object will be instantiated and called as such:
- MyHashMap obj = new MyHashMap();
- obj.put(key,value);
- int param_2 = obj.get(key);
- obj.remove(key);
*/
题解:
给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: rowIndex = 3
输出: [1,3,3,1]
示例 2:
输入: rowIndex = 0
输出: [1]
示例 3:
输入: rowIndex = 1
输出: [1,1]
提示:
0 <= rowIndex <= 33
代码:
class Solution {
public List<Integer> getRow(int rowIndex) {
List<List<Integer>> list=new ArrayList<List<Integer>>();
for(int i=0;i<=rowIndex;i++){
List<Integer> li=new ArrayList<>();
for(int j=0;j<i+1;j++){
if(j==0||j==i){
li.add(1);
}else{
li.add(list.get(i-1).get(j-1)+list.get(i-1).get(j));
}
}
list.add(li);
}
return list.get(rowIndex);
}
}
题解:
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:
输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
提示:
n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000
代码:
class Solution {
public void rotate(int[][] matrix) {
int n=matrix.length;
int [][] ans=new int [n][n];
//第i行第j列的-->倒数第i(n-1-i)列,第j行
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
ans[j][n-1-i]=matrix[i][j];
}
}
//再赋值给原数组
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
matrix[i][j]=ans[i][j];
}
}
}
}
题解:
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例 1:
输入: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
示例 2:
输入: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 = 20
输出:false
提示:
m == matrix.length
n == matrix[i].length
1 <= n, m <= 300
-109 <= matrix[i][j] <= 109
每行的所有元素从左到右升序排列
每列的所有元素从上到下升序排列
-109 <= target <= 109
代码:
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
for(int i=0;i<matrix.length;i++){
int left=0;
int right=matrix[i].length-1;
while(left<=right){
int mid=(left+right)/2;
if(matrix[i][mid]==target){
return true;
}else if(matrix[i][mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
}
return false;
}
}
题解;
题目及示例
给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
注意:
可以认为区间的终点总是大于它的起点。
区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。
示例 1:
输入: [ [1,2], [2,3], [3,4], [1,3] ]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。
示例 2:
输入: [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
示例 3:
输入: [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。
代码:
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
if(intervals.length==0){
return 0;
}
Arrays.sort(intervals,new Comparator<int[]>(){
public int compare(int [] interval1,int []interval2){
//如果返回值>0交换,即是前面的数字大于后面的数字,则交换,进行升序排列
return interval1[1]-interval2[1];
}
});
int n=intervals.length;
int right=intervals[0][1];
int ans=1;
for(int i=0;i<n;i++){
//此区间左端点如果和上一个区间右端点不重合,那么不移出区间多一个,右端点变成此区间的右端点
if(intervals[i][0]>=right){
ans++;
right=intervals[i][1];
}
}
return n-ans;
}
}
题解:
题目和实例
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给你 n ,请计算 F(n) 。
示例 1:
输入:2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:
输入:3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2
代码:
class Solution {
public int fib(int n) {
if(n==0){
return 0;
}
if(n==1){
return 1;
}
return fib(n-1)+fib(n-2);
}
}
题解:
题目及示例
泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
示例 1:
输入:n = 4
输出:4
解释:
T_3 = 0 + 1 + 1 = 2
T_4 = 1 + 1 + 2 = 4
示例 2:
输入:n = 25
输出:1389537
错误代码(超时)
class Solution {
public int tribonacci(int n) {
if(n==0){
return 0;
}
if(n==1||n==2){
return 1;
}
return tribonacci(n-1)+tribonacci(n-2)+tribonacci(n-3);
}
}
代码:
class Solution {
public int tribonacci(int n) {
if(n==0){
return 0;
}
if(n==1||n==2){
return 1;
}
int p=0,q=0,r=1,s=1;
for(int i=3;i<=n;i++){
p=q;
q=r;
r=s;
s=p+q+r;
}
return s;
}
}
题解
题目及示例
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
3. 1 阶 + 1 阶 + 1 阶
4. 1 阶 + 2 阶
5. 2 阶 + 1 阶
代码
class Solution {
public int climbStairs(int n) {
int p=0,q=0,s=1;
for(int i=1;i<=n;i++){
p=q;
q=s;
s=p+q;
}
return s;
}
}
题解:
题目及示例
给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
请你计算并返回达到楼梯顶部的最低花费。
示例 1:
输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。
示例 2:
输入:cost = [1,100,1,1,1,100,1,1,100,1]
输出:6
解释:你将从下标为 0 的台阶开始。
提示:
2 <= cost.length <= 1000
0 <= cost[i] <= 999
代码1
class Solution {
public int minCostClimbingStairs(int[] cost) {
int n=cost.length;
int []dp=new int[n+1];
dp[0]=0;
dp[1]=0;
for(int i=2;i<=n;i++){
dp[i]=Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
}
return dp[n];
}
}
代码2(优化)
class Solution {
public int minCostClimbingStairs(int[] cost) {
int n=cost.length;
int prev=0,curr=0;
for(int i=2;i<=n;i++){
int next=Math.min(curr+cost[i-1],prev+cost[i-2]);
prev=curr;
curr=next;
}
return curr;
}
}
题解
题目及示例
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 400
代码:
class Solution {
public int rob(int[] nums) {
int n=nums.length;
if(n==0){
return 0;
}
if(n==1){
return nums[0];
}
int [] dp=new int[nums.length];
dp[0]=nums[0];
dp[1]=Math.max(nums[0],nums[1]);
for(int i=2;i<n;i++){
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[n-1];
}
}
题解:
题目及示例
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
示例 1:
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:
输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 3:
输入:nums = [0]
输出:0
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 1000
代码
class Solution {
public int rob(int[] nums) {
int n=nums.length;
if(n==0){
return 0;
}
if(n==1){
return nums[0];
}
if(n==2){
return Math.max(nums[0],nums[1]);
}
return Math.max(robRange(0,n-2,nums),robRange(1,n-1,nums));
}
public int robRange(int start,int end,int nums[]){
int first=nums[start];
int second=Math.max(nums[start],nums[start+1]);
for(int i=start+2;i<=end;i++){
int tmp=Math.max(second,first+nums[i]);
first=second;
second=tmp;
}
return second;
}
}
题解
题目及示例
给你一个整数数组 nums ,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除 所有 等于 nums[i] - 1 和 nums[i] + 1 的元素。
开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。
示例 1:
输入:nums = [3,4,2]
输出:6
解释:
删除 4 获得 4 个点数,因此 3 也被删除。
之后,删除 2 获得 2 个点数。总共获得 6 个点数。
示例 2:
输入:nums = [2,2,3,3,3,4]
输出:9
解释:
删除 3 获得 3 个点数,接着要删除两个 2 和 4 。
之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。
总共获得 9 个点数。
提示:
1 <= nums.length <= 2 * 10^4
1 <= nums[i] <= 10^4
代码:
class Solution {
public int deleteAndEarn(int[] nums) {
int max=0;
for(int val:nums){
max=Math.max(max,val);
}
int []sum=new int[max+1];
for(int val:nums){
sum[val]+=val;
}
return rob(sum);
}
public int rob(int[] nums) {
int first=nums[0];
int second=Math.max(nums[0],nums[1]);
for(int i=2;i<nums.length;i++){
int tmp=second;
second=Math.max(first+nums[i],second);
first=tmp;
}
return second;
}
}
题解:
题目及示例
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例 1:
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
提示:
1 <= nums.length <= 3 * 10^4
0 <= nums[i] <= 10^5
代码:
class Solution {
public boolean canJump(int[] nums) {
int n=nums.length;
int max=nums[0];
if(n==1){
return true;
}
for(int i=1;i<n;i++){
if(i<=max){
max=Math.max(max,i+nums[i]);
if(max>=n-1){
return true;
}
}
}
return false;
}
}
题解:
题目及示例
给你一个非负整数数组 nums ,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。
示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: nums = [2,3,0,1,4]
输出: 2
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 1000
代码:
class Solution {
public int jump(int[] nums) {
int p=nums.length-1;
int count=0;
while(p>0){
for(int i=0;i<p;i++){
if(i+nums[i]>=p){
p=i;
count++;
break;
}
}
}
return count;
}
}
题解:
题目及示例
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
提示:
1 <= nums.length <= 105
-104<= nums[i] <= 104
代码:
class Solution {
public int maxSubArray(int[] nums) {
int []a=new int[nums.length+1];
a[0]=nums[0];
for(int i=1;i<nums.length;i++){
if(a[i-1]+nums[i]>nums[i]){
a[i]=a[i-1]+nums[i];
}else{
a[i]=nums[i];
}
}
int max=a[0];
for(int i=1;i<nums.length;i++){
if(a[i]>max){
max=a[i];
}
}
return max;
}
}
题解:
题目及示例
给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
代码:
class Solution {
public int maxProduct(int[] nums) {
int max=nums[0],min=nums[0],ans=nums[0];
int n=nums.length;
for(int i=1;i<n;i++){
int mx=max,mn=min;
max=Math.max(mx*nums[i],Math.max(mn*nums[i],nums[i]));
min=Math.min(mn*nums[i],Math.min(mx*nums[i],nums[i]));
ans=Math.max(ans,max);
}
return ans;
}
}
题解:
题目及示例
给你一个正整数数组 values,其中 values[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的 距离 为 j - i。
一对景点(i < j)组成的观光组合的得分为 values[i] + values[j] + i - j ,也就是景点的评分之和 减去 它们两者之间的距离。
返回一对观光景点能取得的最高分。
示例 1:
输入:values = [8,1,5,2,6]
输出:11
解释:i = 0, j = 2, values[i] + values[j] + i - j = 8 + 5 + 0 - 2 = 11
示例 2:
输入:values = [1,2]
输出:2
提示:
2 <= values.length <= 5 * 104
1 <= values[i] <= 1000
代码:
class Solution {
public int maxScoreSightseeingPair(int[] values) {
int n=values.length;
int ans=0;
int max=values[0]+0;
for(int j=1;j<n;j++){
ans=Math.max(ans,max+values[j]-j);
max=Math.max(max,values[j]+j);
}
return ans;
}
}
题解:
题目及示例
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
代码1:
class Solution {
public int maxProfit(int[] prices) {
int n=prices.length;
if(n==0){
return 0;
}
//f[i][0]:手中持有股票的最大收益
//f[i][1]:手中不持有股票,并且处于冷冻期内
//f[i][3]:手中不持有股票,并且不处于冰冻期内
int [][]f=new int[n][3];
f[0][0]=-prices[0];//手中持有股票收益是第一天收购股票的价格负值
for(int i=1;i<n;i++){
//手中持有股票:1、前一天可以是持有股票,2、也可以是不持有股票不处于冷冻期.当天买入
f[i][0]=Math.max(f[i-1][0],f[i-1][2]-prices[i]);
//手中不持有股票,并且处于冷冻期内:1、当天卖出,前一天持有股票 ,获得当天卖出股票的钱
f[i][1]=f[i-1][0]+prices[i];
//手中不持有股票,并且不处于冷冻期内:1、前一天不持有股票不处于冷冻期 2、前一天不持有股票处于冷冻期
f[i][2]=Math.max(f[i-1][2],f[i-1][1]);
}
//最后一天还没有出售掉股票是没有意义的
return Math.max(f[n-1][1],f[n-1][2]);
}
}
代码2(空间优化):
题解:
题目及示例
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
示例 1:
输入: s = “leetcode”, wordDict = [“leet”, “code”]
输出: true
解释: 返回 true 因为 “leetcode” 可以由 “leet” 和 “code” 拼接成。
示例 2:
输入: s = “applepenapple”, wordDict = [“apple”, “pen”]
输出: true
解释: 返回 true 因为 “applepenapple” 可以由 “apple” “pen” “apple” 拼接成。
注意,你可以重复使用字典中的单词。
示例 3:
输入: s = “catsandog”, wordDict = [“cats”, “dog”, “sand”, “and”, “cat”]
输出: false
提示:
1 <= s.length <= 300
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 20
s 和 wordDict[i] 仅有小写英文字母组成
wordDict 中的所有字符串 互不相同
代码:
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
Set<String> wordDictSet=new HashSet(wordDict);
boolean []dp=new boolean[s.length()+1];
dp[0]=true;
for(int i=1;i<=s.length();i++){
for(int j=0;j<i;j++){
if(dp[j]&&wordDictSet.contains(s.substring(j,i))){
dp[i]=true;
break;
}
}
}
return dp[s.length()];
}
}
题解:
tim
如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。
例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。
给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。
子数组 是数组中的一个连续序列。
示例 1:
输入:nums = [1,2,3,4]
输出:3
解释:nums 中有三个子等差数组:[1, 2, 3]、[2, 3, 4] 和 [1,2,3,4] 自身。
示例 2:
输入:nums = [1]
输出:0
提示:
1 <= nums.length <= 5000
-1000 <= nums[i] <= 1000
错误代码
class Solution {
public int numberOfArithmeticSlices(int[] nums) {
int n=nums.length;
int total=0;
if(n<3){
return 0;
}
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int i=0;i<n-1;i++){
map.put(nums[i+1]-nums[i],map.getOrDefault(nums[i+1]-nums[i],0)+1);
}
for(Map.Entry<Integer,Integer> entry:map.entrySet()){
int num=entry.getValue();
total+=jie(num-1);
System.out.println(num);
}
return total;
}
public int jie(int num){
// if(num==1){
// return 1;
// }
// return num+jie(num-1);
int total=0;
for(int i=1;i<=num;i++){
total+=num;
}
return total;
}
}
正确代码:
class Solution {
public int numberOfArithmeticSlices(int[] nums) {
int n=nums.length;
int total=0;
if(n<3){
return total;
}
int d=nums[0]-nums[1];
int t=0;
for(int i=2;i<n;i++){
if(nums[i-1]-nums[i]==d){
++t;
}else{
d=nums[i-1]-nums[i];
t=0;
}
total+=t;
}
return total;
}
}
题解: