LeetCode 45跳躍遊戲&46全排列

bigsai發表於2020-10-25

原創公眾號: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 更多精彩和資源與你分享。
在這裡插入圖片描述

相關文章