Preguntas de cepillado diario (5) - preguntas de retroceso: Reina N, resolución de Sudoku, reorganización del itinerario

El título de este artículo proviene de leetcode y codifica pensamientos aleatorios.

prefacio

Hola a todos, soy Xiaoyu, hice la parte de retroceso de la grabación aleatoria del código hoy, y tres preguntas difíciles consecutivas son muy valiosas. Este artículo hablará sobre estas tres preguntas difíciles:

51. Reina N - Leetcode

37. Resolver Sudoku - Leetcode

332. Reorganizar itinerario - Leetcode

Pregunta 51. Reina N

De acuerdo con las reglas del ajedrez, una reina puede atacar una pieza que esté en la misma fila o columna o en la misma diagonal que la reina.

El problema de las n reinas estudia cómo colocar nn reinas n×nen el tablero de ajedrez para que las reinas no puedan atacarse entre sí.

Dado un número entero , devuelva todas las soluciones ndiferentes al problema de n-reinas .

Cada solución consiste en un esquema de colocación de peones diferente para el problema de las n-reinas , donde 'Q'y '.'representan la reina y el espacio abierto, respectivamente.

Ejemplo 1:

输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:'Q'表示皇后位置,'.'表示空位置,如图,4 皇后问题存在两个不同的解法。

pista:

  • 1 <= n <= 9

Solución

Esta pregunta es un problema clásico de retroceso. Comenzamos colocando reinas en la primera fila, intentamos colocar reinas en cada posición, luego recurrimos a la siguiente fila y continuamos intentando colocar reinas hasta que todas las filas estén llenas o no se puedan colocar reinas. . Si no puede encontrar una posición adecuada para colocar la reina en una fila determinada, debe volver a la fila anterior e intentar colocar la reina en otra posición en la fila anterior. Al implementar el algoritmo de retroceso, debe usar una matriz temporal para registrar la posición de la reina en cada fila y una matriz visitada para registrar si se puede alcanzar la posición actual. El código específico para la implementación es el siguiente:

Código

func getResult(temp []int)[]string{
	var result []string
	n:=len(temp)

	for i := 0; i < len(temp); i++ {
		var s []byte
		for j := 0; j < n; j++ {
			if j == temp[i]{
				s = append(s,'Q')
			}else{
				s = append(s,'.')
			}

		}
		result =append(result,string(s))
	}


	return result
}


func solveNQueens(n int) [][]string {
	var temp []int
	var result [][]string
	
	visited := make([][]int,n)
	for i := 0; i < len(visited); i++ {
		visited[i] = make([]int,n)
	}
	
	var dfs func(index int)
	dfs = func(index int) {
		if len(temp) == n {
			fmt.Println(temp)
			result = append(result,getResult(temp))
			return 
		}

		for i := 0; i < n; i++ {
			if visited[index][i] > 0 {
				continue
			}
			//修改visited数组
			for j := 0; j < n; j++ {
				visited[index][j]++
			}
			for j := 0; j < n; j++ {
				visited[j][i]++
			}
			//斜右下
			x,y:=index+1,i+1
			for x < n && y < n {
				visited[x][y]++
				x++
				y++
			}
			//斜左下
			x,y = index+1,i-1
			for x < n && y >= 0 {
				visited[x][y]++
				x++
				y--
			}
			//放入temp中
			temp = append(temp,i)
			dfs(index+1)
			//还原visited数组
			//修改visited数组
			for j := 0; j < n; j++ {
				visited[index][j]--
			}
			for j := 0; j < n; j++ {
				visited[j][i]--
			}
			//斜右下
			x,y = index+1,i+1
			for x < n && y < n {
				visited[x][y]--
				x++
				y++
			}
			//斜左下
			x,y = index+1,i-1
			for x < n && y >= 0 {
				visited[x][y]--
				x++
				y--
			}
			//还原temp
			temp = temp[:len(temp)-1]
		}
	}
    dfs(0)
	return result
	
}

Pregunta 37. Resolviendo Sudoku

Escriba un programa que resuelva problemas de Sudoku llenando los espacios en blanco.

La solución de Sudoku debe seguir las siguientes reglas :

  1. 1-9Los números solo pueden aparecer una vez por línea.
  2. Los números solo pueden aparecer una vez 1-9en cada columna.
  3. 1-9Los números 3x3solo pueden aparecer una vez en cada palacio separados por una línea continua gruesa. (Consulte la imagen de ejemplo)

Los números se han llenado en los espacios en blanco de la parte de Sudoku, y los espacios en blanco se '.'indican .

Ejemplo 1:

输入:board = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]
输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]]

pista:

  • board.length == 9
  • board[i].length == 9
  • board[i][j]es un solo dígito o'.'
  • Datos de la pregunta Garantía de que el Sudoku de entrada tiene una sola solución

Solución

Resolver problemas de Sudoku también puede usar un algoritmo de retroceso, similar al problema de N Queens. Comience desde el primer espacio, intente completar el número 1-9 en esa posición , luego recurra al siguiente espacio , continúe tratando de completar los números hasta que se llenen todos los espacios o no se puedan completar más números. Si no puede encontrar un número adecuado para completar un espacio determinado, debe volver al espacio anterior e intentar completar otros números. Al implementar, necesitamos definir tres matrices adicionales para registrar la ocurrencia de números en horizontal, vertical y cuadrícula.La implementación específica es la siguiente:

Código

func solveSudoku(board [][]byte)  {
	hvisited := make([][]int,9)
	svisited := make([][]int,9)
	xvisited := make([][]int,9)
	for i := 0; i < 9; i++ {
		hvisited[i] = make([]int,10)
		svisited[i] = make([]int,10)
		xvisited[i] = make([]int,10)
	}
	//初始化visited数组
	for i := 0; i < len(board); i++ {
		for j := 0; j < len(board[i]); j++ {
			temp:=board[i][j]
			if temp != '.'{
				hvisited[i][temp-'0']++
				svisited[j][temp-'0']++
				xvisited[(i/3)*3+(j/3)][temp-'0']++
			}
		}
	}


	var help func(x,y int)(int,int) = func(x, y int) (int, int) {
		x += y/9
		y %= 9
		return x,y
	}
	var visited func(x,y,i int)bool = func(x,y,i int)bool{
		if hvisited[x][i] >0 || svisited[y][i] > 0 || xvisited[(x/3)*3+(y/3)][i]>0{
			return true
		}else {
			return false
		}
	}
     
	var dfs func(x,y int)bool
	dfs = func(x, y int) bool{

		if x == 9 {
			return true
		}

		if board[x][y] != '.'{
			if dfs(help(x,y+1)){
				return true
			}
		}else{
	        for i := 1; i <= 9; i++ {
		 if visited(x,y,i){
			 continue
		 }

			hvisited[x][i]++
			svisited[y][i]++
			xvisited[(x/3)*3+(y/3)][i]++
			board[x][y] = byte('0'+i) 
			if dfs(help(x,y+1)){
				return true
			}
			board[x][y] = byte('.')
			hvisited[x][i]--
			svisited[y][i]--
			xvisited[(x/3)*3+(y/3)][i]--
		}
        }

	return false
	}
	
	dfs(0,0)
	
}

Pregunta 332. Reprogramar

Se le proporciona una lista de rutas de vuelo tickets, donde tickets[i] = [fromi, toi]está el aeropuerto donde sale y aterriza el avión. Vuelva a planificar el itinerario.

Todos estos boletos pertenecen a un JFKSr. con salida desde (JFK), por lo que el viaje debe JFKcomenzar . Si hay varios itinerarios válidos, devuelva la combinación de itinerario más pequeña según el diccionario.

  • Por ejemplo, el ["JFK", "LGA"]viaje ["JFK", "LGB"]es más pequeño y está ordenado más alto que .

Se supone que todos los boletos tienen al menos un itinerario razonable. Y todos los boletos deben usarse una vez y solo una vez.

Ejemplo 1:

输入:tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
输出:["JFK","MUC","LHR","SFO","SJC"]

pista:

  • 1 <= tickets.length <= 300
  • tickets[i].length == 2
  • fromi.length == 3
  • toi.length == 3
  • fromiy se componen toide letras inglesas mayúsculas
  • fromi != toi

Solución

En esta pregunta, defina un hashmap para almacenar el mapeo entre estaciones y estaciones de llegada. Primero, recorra el boleto, almacene el mapeo de la estación de salida y la estación de llegada en el boleto, comience desde el punto de partida, pruebe cada boleto por turno y verifique si cumple con los requisitos (es decir, el aeropuerto actual es el punto de partida, y este billete no ha sido utilizado), si cumple los requisitos se añade a la ruta actual y sigue buscando el siguiente aeropuerto, si no cumple los requisitos vuelve al aeropuerto anterior y sigue intentando otros billetes. Cuando la longitud de la ruta es igual al número de aeropuertos, significa que hemos encontrado una ruta legal (tenga en cuenta que el título requiere que se devuelva la combinación de itinerario más pequeña mediante la clasificación del diccionario, por lo que si las estaciones de llegada en el mapa están ordenadas en avance, luego el primero atravesado El resultado es el resultado con el orden lexicográfico más pequeño), solo devuelve el resultado.

Código

func findItinerary(tickets [][]string) []string {
	m := make(map[string][]string)
	var result []string
	var temp []string
	var dfs func(s string)
	var flag bool
	for i := 0; i < len(tickets); i++ {
		m[tickets[i][0]] = append(m[tickets[i][0]],tickets[i][1])
	}
 
	for _,v:=range m {
		sort.Slice(v, func(i, j int) bool {
			if v[i] < v[j]{
				return true
			}else{
				return false
			}
		})
	}
	temp = append(temp,"JFK")
	dfs = func(s string) {
		if flag {
			return 
		}
		if len(temp) == len(tickets)+1{
			result = make([]string,len(temp))
            copy(result,temp)
			flag = true
			return
		}
		for i,v:=range m[s]{
            if v =="-1"{
                continue
            }
           
			temp = append(temp,v)
              m[s][i] = "-1"
			dfs(v)
			temp = temp[:len(temp)-1]
            m[s][i] = v
		}
	}
	dfs("JFK")
	return result
}

Resumir

Al realizar un seguimiento de temas, es mejor poder dibujar un diagrama de árbol , determinar la ruta de seguimiento y hacer una simulación aproximada de todo el tema . Si la simulación es exitosa, puede comenzar a darse cuenta . Al implementar, defina alguna información de estado y luego escriba una función de retroceso. Tenga en cuenta que el recorrido horizontal está controlado por el bucle for , y la recursión vertical está controlada por la función dfs . Finalmente, las operaciones de reducción de rama se pueden realizar para cada tipo de ¡tema!

Supongo que te gusta

Origin blog.csdn.net/doreen211/article/details/129496586
Recomendado
Clasificación