当数字大到超过long的范围后是会发生溢出的,所以在这里把它当作字符串进行处理。按照正常的思路,我们自己在计算数字相加的时候,从低位开始,每次记录当前的进位,与下两个数字相加,当思路清晰了,解决问题的方法也就简单明了
代码如下:
public static String BigNumberPlus(String one,String two){
int lengthOne = one.length() , lengthTwo = two.length() , length = lengthOne;
String leaveStr = "" ;
if(lengthOne < lengthTwo){
length = lengthOne;
leaveStr = two.substring(0,lengthTwo- length);
}
else{
length = lengthTwo;
leaveStr = one.substring(0,lengthOne - length);
}
String res = "";
int mod = 0;
for(int i = length - 1;i >= 0;i--){
int o = one.charAt(i) - '0';
int t = two.charAt(i) - '0';
int temp = o + t + mod;
res += temp % 10;
mod = temp / 10;
}
for(int i = leaveStr.length() - 1;i >= 0;i--){
int l = leaveStr.charAt(i);
int temp = l + mod;
res += temp % 10;
mod = temp / 10;
}
return new StringBuilder(res).reverse().toString();
}
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
例如,上图是一个7 x 3 的网格。有多少可能的路径?
说明:m 和 n 的值均不超过 100。
示例 1:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例 2:
输入: m = 7, n = 3
输出: 28
思路:动态规划,因为只能向右,或者向下搜索。反过来看,会发现所在的路线都一定会经历,起点所在的行与列上,也就是road[0][i]、road[i][0]。并且设置最开始road[0][0] = 1;(i,j)所在位置只和左边和上边有关系;即road[i][j] = road[i][j-1] + road[i-1][j];
代码如下:
public int uniquePaths(int m, int n) {
int [][]dp = new int[m][n];
dp[0][0] = 1;
for(int i = 0;i < m;i++)
for(int j = 0;j < n;j++){
if(i - 1 >= 0)
dp[i][j] += dp[i-1][j];
if(j - 1 >= 0)
dp[i][j] += dp[i][j-1];
}
return dp[m-1][n-1];
}
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
说明:m 和 n 的值均不超过 100。
示例 1:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
思路:
与上面一个题思路大致相同,不过由于多了障碍,所以多了障碍判断,其次由于障碍物设置为1,那么就把初始值设置为-1,最后求反即可
代码如下:
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int rows = obstacleGrid.length;
int cols = obstacleGrid[0].length;
obstacleGrid[0][0] = -1;
for(int i = 0;i < rows;i++)
for(int j = 0;j < cols;j++){
if(obstacleGrid[i][j] != 1){
if((i - 1) >= 0 && obstacleGrid[i-1][j] != 1){
obstacleGrid[i][j] += obstacleGrid[i-1][j];
}
if((j-1) >= 0 && obstacleGrid[i][j-1] != 1)
obstacleGrid[i][j] += obstacleGrid[i][j-1];
}
}
return obstacleGrid[rows-1][cols-1] * -1;
}
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
示例 1:
输入: [2,3,1,1,4]
输出: true
解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。
示例 2:
输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
思路:
根据题目描述,我们首先想到求解思路是贪心算法,着个遍历每种走法,直到成功跳出后返回。对于当下的i,存在nums[i]种走法,那么我们逐个往前推进即可
代码如下:
/**
* 55. 跳跃游戏
* @param nums
* @return
*/
boolean res = false;
public boolean canJump(int[] nums) {
return canJump(nums,0,nums.length - 1);
}
public boolean canJump(int []nums,int start,int road){
if(nums[start] >= road)
return true;
else{
for(int i = 1;i <= nums[start];i++){
if(res)
return res;
res |= canJump(nums,start + i,road - i);
}
}
return res;
}
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
思路:
剔除题目背景是股票买卖(其描述,显然不符合实际市场环境),其真是表达的意思是,求连续最长递增序列。理解了题目意思,代码写起来就比较容易了。记录每次买入点start,卖出点end,累计求和
/**
* 122. 买卖股票的最佳时机 II
* @param prices
* @return
*/
public static int maxProfit(int[] prices) {
int lg = prices.length;
int res = 0 , start = 0 , end = 0;
for(int i = 1;i < lg;i++){
if(prices[i] > prices[i-1]){
end =i;
}
else{
res += prices[end] - prices[start];
start = i;
}
}
return res;
}
时间复杂度O(n)、空间复杂度O(1)
给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
思路:
k个一组,对每一组的数据进行进行逆转。也就是将一条链表分为k组,逆转的片段,递归的向后链接剩余的片段。
ListNode p = head,q = head.next,r = q.next;
q.next = p;
p = q;
q = r;
给定一个无序数组,包含正数、负数和0,要求从中找出3个数的乘积,使得乘积最大,要求时间复杂度:O(n),空间复杂度:O(1)
输入描述:
第一行是数组大小n,第二行是无序整数数组A[n]
输出描述:
满足条件的最大乘积
输入例子1:
4
3 4 1 2
输出例子1:
24
方法一:通过对n个数排序,第0,1个数的乘积(s1)和第n-3,n-2个数的乘积(s2),取s1、s2中的最大者,并且和最大值n-1相乘,得到最大的3个数乘积之和; 时间复杂度为O(n*logn),空间复杂度为O(n)
方法二:通过建立大小为3的小根堆,维持最大的3个数,建立大小为2的小根堆维持最小的两个数,接下来的比较方法同方法一;时间复杂度为接近O(n)
代码如下:
/**
* [编程题] 最大乘积
*/
public static int test6(){
Scanner sc = new Scanner(System.in);
PriorityQueuemax = new PriorityQueue(2, new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
PriorityQueuemin = new PriorityQueue<>(3);
int n = sc.nextInt() , temp;
for(int i = 0;i < n;i++){
temp = sc.nextInt();
if(min.size() < 3)
min.offer(temp);
else{
if(temp > min.peek()){
min.poll();
min.offer(temp);
}
}
if(max.size() < 2)
max.offer(temp);
else{
if(temp < max.peek()){
max.poll();
max.offer(temp);
}
}
}
int res1 = 1 , res2 = 1;
int tt = -1;
for(Integer it : min){
res1 *= it;
tt = tt > it ? tt : it;
}
res2 *= tt;
for(Integer it : max){
res2 *= it;
}
return res1 > res2 ? res1 : res2;
}