꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ ა
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
系列专栏:xiaoxie的牛客网刷题系列专栏——CSDN博客●'ᴗ'σσணღ*
我的目标:"团团等我💪( ◡̀_◡́ ҂)"
感谢您的阅读!
( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝+关注(互三必回)!
今天在牛客网刷题时,碰到了两题,虽然很简单,但是往深处想,又有不一样的见解,所以博主就把感想写下来分享给大家
首先请先看题
我想很多人和我一样一开始觉得这题不是很简单嘛它的第n项的表达式都给出来了,解决这个问题不是轻松拿捏嘛直接
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); // 注意 hasNext 和 hasNextLine 的区别 while (in.hasNextInt()) { // 注意 while 处理多个 case int n = in.nextInt(); double a =0; double b = 0; for(int i=1;i<=n;i++){ b=b+Math.pow(-1,i-1)*(2*i-1); a=a+1.0/b; } System.out.printf("%.3f",a); } } }
这样是可以算出答案的,但博主突然灵机一动,把分母的值算出来看一下就发现原来算出来之后,是有规律的啊
它的分母计算出来之后是 1 + -2 +3 -4 +5 -6+......既然知道了分母是这样的规律那我们就可以稍微的简化一下代码
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); double sum = 0.0; int flag = 1; for (int i = 1; i <= n; i++) { sum +=flag*(1.0/i); flag = -flag; } System.out.printf("%.3f", sum); } }
虽然说两个方法不见得谁比谁好,特别是我修改后的代码也算是属于投机取巧,但博主想说的是,抛开这个问题不讲,在我们平时做题的时候多角度的看待问题,我觉得值得提倡
还有一题也是非常简单的一题
也是一样一开始博主是这样写的使用两个for循环来解
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc=new Scanner(System.in); int x=sc.nextInt(); int count=0; for(int i=1;i<=x;i++){ int sum=0; for(int j=1;j<=i;j++){ sum+=j; } count+=sum; } System.out.println(count);
写完后博主突然发现这题不是可以用初高中的数学知识用求前n项和来解这题嘛于是博主修改一下代码,使用公式S=n*(n+1)/2 来解
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int sum = 0; for (int i = 1; i <= n; i++) { sum += (i * (i + 1)) / 2; } System.out.println(sum); } }
其实这题一样也是说不上修改就比没修改的代码性能好到那里去,但是博主觉得在我们平常编译代码的时候,用一用数学的公式可以替我们简化一些代码,并且能够在解题时拓展我们的思维
让我们更好地理解数学公式优化代码。所以,下面来看一下这道题的解法。
首先,我们来看一下题目要求的函数:
public boolean canJump(int[] nums) { // TODO: Implement the logic here return false; // Placeholder return statement }
题目要求我们实现一个函数,判断一个数组 nums
中的元素能否跳跃到最后一个位置。而我们需要通过修改代码来使得函数的执行效率尽可能高。
接下来,我们来分析一下题目的思路。对于这道题,我们可以采用贪心算法的思路来解决。我们遍历数组中的每个位置,并实时维护能够跳跃到的最远位置。对于当前遍历到的位置,如果它在能够跳跃到的最远位置的范围内,那么我们就更新能够跳跃到的最远位置,否则,我们就判断当前位置是否能够跳跃到最远位置,如果不能,就直接返回 False。最后,如果我们遍历完了整个数组,且能够跳跃到最远位置,那么就返回 True。
具体思路可以用以下代码来实现:
public boolean canJump(int[] nums) { int n = nums.length; int maxPos = nums[0]; // 可以到达的最远位置 for (int i = 1; i < n; i++) { if (maxPos >= i) { // 如果当前位置可以到达 maxPos = Math.max(maxPos, i + nums[i]); // 更新最远能到达的位置 if (maxPos >= n - 1) { // 如果已经到达数组末尾 return true; } } else { return false; // 如果当前位置不能到达,直接返回 false } } return false; // 遍历完整个数组都没有到达数组末尾,直接返回 false }
这段代码的时间复杂度为 O(n),因为我们只需要遍历一次整个数组就能得到结果。但是,我们可以通过一些数学公式来简化代码,使得时间复杂度更低。
我们观察一下上面的代码:
maxPos = Math.max(maxPos, i + nums[i]);
我们在更新 max_pos
时,计算的是当前位置可以到达的最远位置 i + nums[i]
和已经可以到达的最远位置 max_pos
中的较大值。这里,我们可以使用一个变量来维护可以到达的最远位置,并且不用每次都调用 max
函数来更新它。
具体操作是,我们令一个整数变量 end
记录当前能够到达的最远位置,而变量 max_pos
则记录已经遍历过的位置中能够到达的最远位置。当我们遍历到位置 i
时,如果 i > end
,那么说明当前位置无法到达,直接返回 False。否则,我们更新 end
的值为 max(end, i + nums[i])
,然后判断更新后的 end
是否已经达到数组的末尾,如果是,就返回 True。
具体实现如下:
public boolean canJump(int[] nums) { int n = nums.length; int end = 0; // 当前能够到达的最远位置 for (int i = 0; i < n; i++) { if (i > end) { // 当前位置无法到达 return false; } end = Math.max(end, i + nums[i]); // 更新能够到达的最远位置 if (end >= n - 1) { // 如果已经到达末尾位置 return true; } } return true; }
这段代码的时间复杂度为 O(n),但是和上面的代码相比,更加简洁。这就是利用数学公式优化代码的方法。
谢谢大家的阅读!