数字序列中某一位的数字
题目
题解
代码:
public int findNthDigit(int n) {
int digit=1;
long start=1;
long count=9;
while(n>count){
n-=count;
start*=10;
digit+=1;
count=digit*start*9;
}
long num=start+(n-1)/digit;
return Long.toString(num).charAt((n-1)%digit)-'0';
}
把数字翻译成字符串
题目
题解
【方法一】:时间复杂度O(N),空间复杂度O(N)
思路:先将数字转成字符串,遍历字符串统计可能得翻译种数
dp[i]的含义为以第i个字符结尾的子串可能的翻译种数
转移方程:
(1)dp[i]=dp[i-1]+dp[i-2] 此情况为第i-1个字符和第i个字符构成的数字在10和25之间
(2)dp[i]=dp[i-1] 此情况为第i-1个字符和第i个字符构成的数字不在10和25之间
因为i位置只与i-1和i-2位置有关,因此我们使用有限个变量迭代的过程替代dp数组
public int translateNum(int num) {
String str=String.valueOf(num);
int b=1;
int a=1;
for(int i=2;i<=str.length();i++){
int tmp=(str.charAt(i-1)-'0')+(str.charAt(i-2)-'0')*10;
int c=tmp>=10&&tmp<=25?a+b:a;
b=a;
a=c;
}
return a;
}
【方法二】:时间复杂度O(N),时间复杂度O(1)
思路:从后往前遍历,省去了将数字转成String类型的空间
public int translateNum(int num) {
int a=1;
int b=1;
int x;
int y=num%10;
while(num!=0){
num/=10;
x=num%10;
int tmp=x*10+y;
int c=tmp>=10 && tmp<=25?a+b:a;
b=a;
a=c;
y=x;
}
return a;
}
礼物的最大价值
题目
题解
代码:
public int maxValue(int[][] grid) {
int n=grid.length;
int m=grid[0].length;
int[][] dp=new int[n][m];
dp[0][0]=grid[0][0];
for(int i=1;i<n;i++){
dp[i][0]=dp[i-1][0]+grid[i][0];
}
for(int j=1;j<m;j++){
dp[0][j]=dp[0][j-1]+grid[0][j];
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
return dp[n-1][m-1];
}
最长不含重复字符的子串
题目
题解
方法一:双指针+滑动窗口
public int lengthOfLongestSubstring(String s) {
int l=0;
int r=0;
int max=0;
Set<Character> set=new HashSet<>();
while(r<s.length()){
if(!set.contains(s.charAt(r))){
set.add(s.charAt(r));
r++;
max=Math.max(max,r-l);
}else {
while(set.contains(s.charAt(r))){
set.remove(s.charAt(l));
l++;
}
set.add(s.charAt(r));
r++;
}
}
return max;
}
方法二:动态规划+哈希表
dp[j]含义为以j位置字符结尾的不含重复字符的子串长度
转移方程:对于j位置字符来说,通过map得到离j位置最近的相同字符s[i]
(1)如果i小于0,说明s[j]左边不含与s[j]相同的字符
(2)dp[j-1]<j-i,说明s[i]在dp[j-1]所包含的子串之外,dp[j]=dp[j-1]+1
(3)dp[j-1]>j-i,说明在dp[j-1]包含的字串中存在于j位置相同的重复字符,因此应以j-i位置为准,dp[j]=j-i
由于dp[j]只与dp[j-1]位置有关,因此使用有限个变量迭代来代替dp数组
public int lengthOfLongestSubstring(String s) {
int ret=0;
int tmp=0;
HashMap<Character,Integer> map=new HashMap<>();
for(int j=0;j<s.length();j++){
int i=map.getOrDefault(s.charAt(j),-1);
map.put(s.charAt(j),j);
tmp=tmp<j-i?tmp+1:j-i;
ret=Math.max(tmp,ret);
}
return ret;
}
丑数
题目
题解
dp[i]的含义为第i个丑数
定义三个指针,p2,p3,p5,表示下一个丑数是当前指针指向的质因子,初始都为1,dp[i]=min(dp[p2]*2,dp[p3]*3,dp[p5]*5),然后分别比较 dp[i]和dp[p2]*2,dp[p3]*3,dp[p5]*5是否相等,相等的话将对相应的指针+1
public int nthUglyNumber(int n) {
int[] dp=new int[n+1];
dp[1]=1;
int p2=1;
int p3=1;
int p5=1;
for(int i=2;i<=n;i++){
int num2=dp[p2]*2;
int num3=dp[p3]*3;
int 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];
}
第一个只出现一次的字符
题目
题解
思路:使用有序的哈希表统计字符串中每个字符的出现次数,由于有序哈希表默认是按照插入顺序进行排序的,因此只需再次遍历哈希表就能得到结果
代码:
public char firstUniqChar(String str) {
//LinkedHashMap 是有序的哈希表,默认顺序为插入顺序
Map<Character,Boolean> map=new LinkedHashMap<>();
char[] s=str.toCharArray();
for(char c:s){
map.put(c,!map.containsKey(c));
}
for(Map.Entry<Character,Boolean> entry:map.entrySet()){
if(entry.getValue()) return entry.getKey();
}
return ' ';
}
数组中的逆序对
题目
题解
代码:
private int count=0;
public int reversePairs(int[] nums) {
mergeSort(nums,0,nums.length-1);
return count;
}
private void mergeSort(int[] nums,int left,int right){
if(left>=right) return;
int mid=(left+right)/2;
mergeSort(nums,left,mid);
mergeSort(nums,mid+1,right);
merge(nums,left,mid,right);
}
private void merge(int[] nums,int left, int mid ,int right){
int[] tmp=new int[right-left+1];
int k=0;
int i=left;
int j=mid+1;
while(i<=mid && j<=right){
if(nums[i]<=nums[j]){
tmp[k++]=nums[i++];
}else {
tmp[k++]=nums[j++];
count+=(mid-i+1);
}
}
while(i<=mid){
tmp[k++]=nums[i++];
}
while(j<=right){
tmp[k++]=nums[j++];
}
for(int val:tmp){
nums[left++]=val;
}
}
两个链表的第一个公共节点
题目
题解
代码:
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode cur1=headA;
ListNode cur2=headB;
while(cur1!=cur2){
cur1=cur1==null?headB:cur1.next;
cur2=cur2==null?headA:cur2.next;
}
return cur2;
}
在排序数组中查找数字
题目
题解
思路:通过二分查找target和target-1的右边界,相减后得到值为target的元素个数
代码:
public int search(int[] nums, int target) {
return helper(nums,target)-helper(nums,target-1);
}
public int helper(int[] nums,int target){
int i=0;
int j=nums.length-1;
while(i<=j){
int mid=(i+j)/2;
if(nums[mid]>target) j=mid-1;
else if(nums[mid]<=target) i=mid+1;
}
return i;
}