原創公眾號:bigsai,回覆進群加入力扣打卡群。
昨日打卡:LeetCode 42字串相乘&43萬用字元匹配
跳躍遊戲
題目描述:
給定一個非負整數陣列,你最初位於陣列的第一個位置。
陣列中的每個元素代表你在該位置可以跳躍的最大長度。
你的目標是使用最少的跳躍次數到達陣列的最後一個位置。
示例:
輸入: [2,3,1,1,4]
輸出: 2
解釋: 跳到最後一個位置的最小跳躍數是 2。
從下標為 0 跳到下標為 1 的位置,跳 1 步,然後跳 3 步到達陣列的最後一個位置。
說明:
假設你總是可以到達陣列的最後一個位置。
分析:
這題的話也是運用了不同的方法,從複雜到簡單。
法一:列舉
列舉的思路很簡單,二重迴圈,第一次迴圈遍歷每個數,第二次迴圈遍歷長度更新這個範圍內能夠更新到的最小跳數。如果能跳到該位置並且跳躍次數更少就更新。演算法想法簡單,初始需要將除第0位其他設定為非常大的值(以便有更小的值進行更新)
實現程式碼為:
public int jump(int[] nums) {
int dp[]=new int[nums.length];
for(int i=1;i<nums.length;i++)
{
dp[i]=Integer.MAX_VALUE;
}
for(int i=0;i<nums.length;i++)
{
int time=dp[i]+1;
for(int j=0;j<nums[i];j++)
{
if(j+i+1<nums.length)
{
if(dp[j+i+1]>time)
dp[j+i+1]=time;
}
}
}
//System.out.println(Arrays.toString(dp));
return dp[nums.length-1];
}
不過效果很糟糕。
法二:bfs
在這條路行不通之後,就開始尋找另一條路。我便想著用優先佇列搜素,具體比較麻煩詳細可以看程式碼,主要講第三種方法:
class node
{
int time;
int index;
public node(int time,int index) {
this.time=time;
this.index=index;
}
}
public int jump(int[] nums) {
boolean jud[]=new boolean[nums.length];
Queue<node>q1=new PriorityQueue<node>(new Comparator<node>() {
@Override
public int compare(node o1, node o2) {
if(o1.time==o2.time)
{
return o2.index-o1.index;
}
return o1.time-o2.time;
}
});
q1.add(new node(0, 0));
while (!q1.isEmpty()) {
node team=q1.poll();
int time=team.time+1;
int index=team.index;
for(int i=1;i<=nums[index];i++)//前進的位置
{
if(index+i<nums.length&&!jud[index+i])
{
if(index+i==nums.length-1)return time;
q1.add(new node(time, index+i));
jud[index+i]=true;
}
}
}
return 0;
}
法三:貪心
當我以為9ms很快的時候,發現原來這個速度還是很慢,就想肯定有一種近O(n)的方法,在這裡索性分享給大家。
我們在這裡需要的實什麼?
- 找到最少的跳躍次數到達最後
影響我們正常計算的最大障礙是什麼?
- 重複計算、覆蓋情況.無論是跳躍方式和跳躍次數到達終點都可能不止一種。
但是有一點非常重要的是:每個節點跳躍的時候是一個從他開始的覆蓋區間範圍,所以我們能否知道第一次跳多遠。第二次跳多遠呢?第三次呢?
很簡單,所有的起始點是0號位置,也就是第一次一定是從0號跳到的一個區間節點。而第二次就是這個區間內能夠跳到的最遠距離都是2次,第三次就是除掉第二次節點後面能夠跳到的區間……這樣一直到能夠覆蓋到最後即可完成。
在具體實現的時候,記錄當前的最大長度,用一個time[]陣列表示到達當前節點需要的跳數,從前往後,如果最大長度大於當前的maxsize,就說明需要加一次更新,如果小於等於maxsize,對應位置則不需要更新。
實現程式碼為:
public int jump(int[] nums) {
int len=nums.length;
int time[]=new int[len];
int maxsize=0;
for(int i=0;i<len;i++)
{
if(i+nums[i]>maxsize)
{
for(int j=maxsize+1;j<=i+nums[i];j++)
{
if(j<len)
{
time[j]=time[i]+1;
maxsize=j;
}
else {
break;
}
}
}
}
return time[len-1];
}
還能優化成1ms的就留給你們來了!
全排列
全排列的兩種實現方式這裡就不累述,大家可以參考:全排列兩種實現方式
實現方式為:
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>>list=new ArrayList<List<Integer>>();
arrange(nums,0,nums.length-1,list);
return list;
}
private void arrange(int[] nums, int start, int end, List<List<Integer>> list) {
if(start==end)
{
List<Integer>list2=new ArrayList<Integer>();
for(int a:nums)
{
list2.add(a);
}
list.add(list2);
}
for(int i=start;i<=end;i++)
{
swap(nums,i,start);
arrange(nums, start+1, end, list);
swap(nums, i, start);
}
}
private void swap(int[] nums, int i, int j) {
int team=nums[i];
nums[i]=nums[j];
nums[j]=team;
}
本次就到這裡啦,個人公眾號:bigsai
回覆 bigsai 更多精彩和資源與你分享。